Перейти к содержанию
    

Покритикуйте

Учусь работать с ацп - решил собрать простейший термометр на аналоговом датчике TC1047 и attiny13, с индикацией на двух семисегметных индикаторах, подключенных через сдвиговой регистр 74HC164. Измеряю от 0 до 60 градусов. результат смотрю в старшем регистре, т.е. 8-битное измерение получается. При использовании внутреннего ИОН 1.1В, шаг получается ~4.3мВ. Результат из преобразованного значения вычисляю как

(x-115)*4/10 - (при нуле градусов датчик дает 500мВ) - получаю значение температуры в градусах. В протеусе работает, но выдает ошибку в 1-3 градуса, чем больше температура тем больше ошибка. Как я понимаю ошибка эта возникает за-за того, что умножаю на 4, а не на 4.3.

Что скажете в целом по схеме и программе? И будет ли все это работать от источника в 3 вольта?

post-72660-1382465712_thumb.jpg

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#define _0 0b11111100	// 0 на индикаторе
#define _1 0b01100000	// 1 на индикаторе
#define _2 0b11011010	// 2 на индикаторе
#define _3 0b11110010	// 3 на индикаторе
#define _4 0b01100110	// 4 на индикаторе
#define _5 0b10110110	// 5 на индикаторе
#define _6 0b10111110	// 6 на индикаторе
#define _7 0b11100000	// 7 на индикаторе
#define _8 0b11111110	// 8 на индикаторе
#define _9 0b11110110	// 9 на индикаторе

#define ADC_start() ADCSRA|=(1<<6)
#define dig_1_off() PORTB|=(1<<4)	//выключение 1 элемента индикатора
#define dig_1_on() PORTB&=(~(1<<4))	//включение 1 элемента индикатора
#define dig_2_off() PORTB|=(1<<0)	//выключение 2 элемента индикатора
#define dig_2_on() PORTB&=(~(1<<0))	//включение 2 элемента индикатора
#define strob_h() PORTB|=(1<<1)		//строб на регистр в 1
#define strob_l() PORTB&=(~(1<<1))	//строб на регистр в 0
static unsigned char temperature_dig_h=0;
static unsigned char temperature_dig_l=0;
ISR(ADC_vect)
{
volatile unsigned char temp=0,temp_h=0,temp_l=0;
temp=ADCH-115;		//из полученного значения вычли значение при 0 градусов
if (temp>=17) temp++;
if (temp>=24) temp++;
if (temp>=31) temp++;
if (temp>=38) temp++;
if (temp>=50) temp++;
if (temp>=60) temp++;
temp=(temp*4)/10;	//умножаем на шаг преобр. ацп (~4мВ) и делим на шаг преобр. датчика (10мВ/градус)

temp_h=temp/10;
temp_l=temp-(temp_h*10);
switch (temp_h)
{
	case 0: temperature_dig_h=_0; break;
	case 1: temperature_dig_h=_1; break;
	case 2: temperature_dig_h=_2; break;
	case 3: temperature_dig_h=_3; break;
	case 4: temperature_dig_h=_4; break;
	case 5: temperature_dig_h=_5; break;
	case 6: temperature_dig_h=_6; break;
	break;
}
switch (temp_l)
{
	case 0: temperature_dig_l=_0; break;
	case 1: temperature_dig_l=_1; break;
	case 2: temperature_dig_l=_2; break;
	case 3: temperature_dig_l=_3; break;
	case 4: temperature_dig_l=_4; break;
	case 5: temperature_dig_l=_5; break;
	case 6: temperature_dig_l=_6; break;
	case 7: temperature_dig_l=_7; break;
	case 8: temperature_dig_l=_8; break;
	case 9: temperature_dig_l=_9; break;
	break;
}
}

int main(void)
{
//Начальная инициализация
//Инициализация АЦП
ADCSRA=0b11101110;		//включение ацп, режим однократного преобразования, разрешение прерывания от ацп,
ADCSRB=0b00000000;		//частота преобразования clk/128=9.6MHz/128=75KHz
ADMUX=0b01100011;		//опорное напряжение - внутренний ИОН 1.1В, рез-т выравнивается влево, вх. канал - ADC3
   //Настройка ввода/вывода
DDRB=0b00010111;
sei();
_delay_us(100);
cli();
while(1)
{
	//вывод данных на 7-сегм. индикаторы. сначала выводится старшая цифра, затем младшая
		//*****
		for (unsigned char counter=1; counter!=0; counter=counter<<1 )
		{
			if ((temperature_dig_h & counter)==0) 
			PORTB&=(~(1<<2));
			else 
			PORTB|=(1<<2);
			strob_h();
			_delay_us(1);
			strob_l();
		}
		dig_1_on();	//активирована 1 цифра
		//sei();
		_delay_us(100);
		//cli();
		dig_1_off();
		for (unsigned char counter=1; counter!=0; counter=counter<<1 )
		{
			if ((temperature_dig_l & counter)==0)
			PORTB&=(~(1<<2));
			else
			PORTB|=(1<<2);
			strob_h();
			_delay_us(10);
			strob_l();
		}

		dig_2_on();
		sei();
		_delay_us(100);
		dig_2_off();
		cli();
		//*****
}
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Учусь работать с ацп - решил собрать простейший термометр на аналоговом датчике TC1047 и attiny13

Вместо Tiny13 возьмите что-нибудь посерьезнее, например, Tiny2313 или Mega88. Тогда и регистр не потребуется.

А почему у вас питание 6В, а не 5 ? И еще, последовательно с сегментами включите токоограничивающие резисторы, по килоому на сегмент, или около того. И еще, необходимость шунтирования базовых резисторов (которые можно было бы увеличить минимум до килоома) конденсаторами мне прдставляется в данном случае более чем сомнительной ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

спасибо за ответ!

tiny2313 не имеет ацп, использую самые простые пока вещи, ну и что есть в наличии

питание я предполагал от 3х вольт (будет ли с ним работать? протеус не желает воспринимать 3 вольта как высокий уровень для подтяжки вверх свободного входа регистра.

токоограничивающие резисторы предполагаются, в протеусе не стал их вносить в проект.

 

 

резисторы в базах рассчитывал как

(Uh-Ue_b)/Ib=(3-0.7)/10^-2=230 ом

Uh - напряжение высокого уровня

Ue_b - падение напряжения на переходе эмиттер-база

Ib - ток базы

 

шунтирования базовых резисторов (которые можно было бы увеличить минимум до килоома) конденсаторами мне прдставляется в данном случае более чем сомнительной

в теории, конденсаторы должны увеличить возможную частоту переключения транзисторов?

в моем случае там около 10кГц должно получиться, конденсаторы и правда не нужны наверно

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как я понимаю ошибка эта возникает за-за того, что умножаю на 4, а не на 4.3.

Что скажете в целом по схеме и программе? И будет ли все это работать от источника в 3 вольта?

Чтобы в рамках целочисленной арифметики умножить на 4.3 нужно сначала умножить на 43 а потом результат поделить на 10. (разумеется, при этом следить за отсутствием переполнения промежуточного результата).

 

Но у Вас проще: для повышения точности сначала все перемножаем, и только потом делим, следим за переполнением.

 

И я бы советовал переписать формулу с использованием дефайнов. собственно код не должен содержать никаких неименованных чисел(констант), только их имена.

 

#define UrefmV  5000   //опорное напряжение АЦП в милливольтах
#define VoltageSlopeOutputResponsemV  10 //милливольт на градус цельсия.
#define NADC  256   //количество отчетов ADC для указанного UrefmV


temperatureC = ((adcCode *  UrefmV) / NADC) /  VoltageSlopeOutputResponsemV;

 

 

Если совсем плохо с вычислительными ресурсами- сделайте предварительно вычисленную табличку на 256 значений, в которой по индексу [adcCode] находится величина temperatureC

 

тогда все вычисление сведется к

temperatureC = TabTemp[adcCode];

 

Кстати, данная таблица может учесть и дополнительные коррекции для этого TC1047, кажется был специальный аппнот с формулой 2-го или 3-го порядка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в моем случае там около 10кГц должно получиться, конденсаторы и правда не нужны наверно

Зачем так много ????? Смело уменьшайте это значение раз эдак в 50 ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чтобы в рамках целочисленной арифметики умножить на 4.3 нужно сначала умножить на 43 а потом результат поделить на 10. (разумеется, при этом следить за отсутствием переполнения промежуточного результата).

спасибо! оказалось все очень просто

Но не меняя тип переменной unsigned char на unsigned int,все получилось без переполнения. Т.е. умножаю значение adc-115 на 43 и делю на 100 - все прекрасно работает. хотя переполнение должно возникнуть при adc-115 >5. Вот здесь момент не ясен

 

но в потеусе с этим простейшим изменением все заработало идеально

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но не меняя тип переменной unsigned char на unsigned int,все получилось без переполнения. Т.е. умножаю значение adc-115 на 43 и делю на 100 - все прекрасно работает. хотя переполнение должно возникнуть при adc-115 >5. Вот здесь момент не ясен
все вычисления над char-ами на самом деле превращаются в вычисления над int-ами, а результат потом усекается до 8 бит, поэтому переполнения и не происходит, если результат умножения не выходит за значение 65535

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

все вычисления над char-ами на самом деле превращаются в вычисления над int-ами, а результат потом усекается до 8 бит, поэтому переполнения и не происходит, если результат умножения не выходит за значение 65535

 

Опасно рассчитывать на подарки судьбы. Лучше не писать код в рассчете на это, а произвести вычисления с интами или лонгами, а в конце преобразовать результат. Иначе при замене компилятора такие чудеса могут начаться. Да и если есть баги в очевидных местах, зачем подставляться там, где недокументированые? Тем более, что их имплементирование неоднозначно.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Опасно рассчитывать на подарки судьбы. Лучше не писать код в рассчете на это, а произвести вычисления с интами или лонгами, а в конце преобразовать результат. Иначе при замене компилятора такие чудеса могут начаться. Да и если есть баги в очевидных местах, зачем подставляться там, где недокументированые? Тем более, что их имплементирование неоднозначно.
я рассчитываю не на подарки судьбы, а на соответствие компилятора стандарту языка Си, который абсолютно однозначно утверждает, что все операнды при вычислениях, размер которых меньше int, приводятся к этому типу, и только затем осуществляется вычисление.

 

если ваш компилятор не следует стандарту - выкиньте его. если вы считаете стандартные возможности языка недокументированными - повышайте свой образовательный уровень.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

внезапно возник вопрос по схеме - по транзисторам. изначально я рассчитывал поставить n-p-n BC817; по высокому уровню на базе транзистор открывается и ток стекает от катода индикатора через коллектор в эмиттер на землю. Но код не менял с самого начала, когда ток стекал от катода индикатора обратно в контроллер, при симуляции в протеусе перепутал транзисторы и поставил p-n-p BC856 и все работало. Вопросы:

как работало в протеусе с p-n-p и будет ли работать как я хотел изначально с n-p-n (при соответствующем изменении программы

на

#define dig_1_on() PORTB|=(1<<4)    //выключение 1 элемента индикатора
#define dig_1_off() PORTB&=(~(1<<4))    //включение 1 элемента индикатора
#define dig_2_on() PORTB|=(1<<0)    //выключение 2 элемента индикатора
#define dig_2_off() PORTB&=(~(1<<0))    //включение 2 элемента индикатора

??

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

по высокому уровню на базе транзистор открывается и ток стекает от катода индикатора через коллектор в эмиттер на землю.

Все так, но тогда придется ставить индикаторы с общим катодом, а не с общим анодом, и npn - транзисторы, как вы и сказали ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

с общим катодом и стоит - для зажигания сегмента выдается 1 на анод и 0 на катод

 

спасибо, работает!

Подскажите еще пожалуйста насчет питания - будет ли вся схема работать от 3 вольт

И каков ток потребление 7-сегментного индикатора? в даташите указан лишь максимальный прямой ток в 30мА - это на сегмент,на цифру или на весь индикатор?

и насколько применимы такие индикаторы в устройствах с батарейным питанием?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите еще пожалуйста насчет питания - будет ли вся схема работать от 3 вольт

Не знаю, хватит ли этого напряжения датчику. МК и индикатору - хватит. Только индикаторы берите красные, они ярче, как правило. Из опыта: при 5-вольтовом питании и килоомных токоограничивающих резисторах сегментов красные индикаторы на две цифры светятся очень ярко. Индикаторы сейчас дома. Через пару часов там буду, посмотрю марку и сюда напишу ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...