WiseLord писал(а):а) void data_convert() - делает не пойми что, но только не разбиение числа на цифры.
Немного подправил расчёт, но всё же.
А как по мне, всё очень даже логично тут. Для примера, представим, что расчёт напряжения у нас вышел 1263 (или же 12,63В. Именно так задумано, без точки): во временную переменную
tmp записываем значение деления на 1000
ADC_res (оно же
value), итого
tmp=1; переменной
adc_data[0] присваиваем значение переменной из массива SEGMENTE[1].
Далее те же пляски с бубном: берём остаток при делении на 1000 (это выходит 263) и делим целочисленно на 100, итого tmp=2; Присваиваем значение переменной из массива SEGMENTE[2] переменной adc_data[1] ... Ну, и так далее.
PS. код подправил, да именно с разбивкой на цифры немного кракозябра была. Сейчас правильно:
Спойлер
/** ФУНКЦИЯ ПРЕОБРАЗОВАНИЯ **/
void data_convert(unsigned int value)
{
unsigned char tmp; // переменная для временного хранения данных преобразования
tmp = value / 1000;
adc_data[0] = SEGMENTE[tmp];
tmp = value % 1000 / 100;
adc_data[1] = SEGMENTE[tmp];
tmp = value % 100 / 10;
adc_data[2] = SEGMENTE[tmp];
tmp = value % 10;
adc_data[3] = SEGMENTE[tmp];
}
WiseLord писал(а):
б) ADC_volt=adc_tmp*4.88; - это просто странно - умножать 8-битные числа на double. Погрешности будут большие. Да и каков смысл? Почему именно 4,88?
Всё очень просто. Расчёт напряжения идёт исходя из 5v максимум (не смотрите, что выше я привёл пример для 12,63 Вольт). Выходит, что цена одной единицы измерения АЦП будет равна 5/1023 = 0,004887585. Однако, для того, чтобы нормально рассчитать вывод значения на индикатор - мне нужно умножить это значение на 1000 (точность до сотых, перед точкой 2 целых). Отсюда и вышло 4,88
WiseLord писал(а):
в) ADCW - это для меня что-то непонятное. Возможно, какая-то очередная неудачная примочка CodeVision, возвращающая 16-битный результат измерения. Хотя вообще-то результат (10-битный) хранится в двух регистрах, ADCH и ADCL, причём первым нужно вычитывать именно ADCL. А присваивать 16-битный ADCW (если это то, что я думаю) 8-битной переменной adc_tmp - это явно неправильно. Если так уж не нужна точность измерения - выравнивайте результат вправо (ADLAR) и читайте ADCH.
По этому поводу уже ответили. ADCW - 10-битное значение ADC. По поводу переменных, спасибо. Тут я тоже напортачил, подправил
char на
int в необходимых местах...
Тем не менее. даже после моих переделок, программа не завелась...
Спойлер
#include <mega8.h>
#include <delay.h>
//Объявляем переменные
//------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80};
volatile unsigned int adc_data[4] = {0,0,0,0};
volatile unsigned int ADC_volt;
/** ФУНКЦИЯ ПРЕОБРАЗОВАНИЯ **/
void data_convert(unsigned int value)
{
unsigned char tmp; // переменная для временного хранения данных преобразования
tmp = value / 1000;
adc_data[0] = SEGMENTE[tmp];
tmp = value % 1000 / 100;
adc_data[1] = SEGMENTE[tmp];
tmp = value % 100 / 10;
adc_data[2] = SEGMENTE[tmp];
tmp = value % 10;
adc_data[3] = SEGMENTE[tmp];
}
void ind_update (void)
{
static unsigned char count = 0;
PORTD = 0x00; // гасим все разряды
PORTD = adc_data[count]; // выводим в порт код цифры
if (count == 0) PORTB |= (1<<0);
if (count == 1) PORTB |= (1<<1); // перечисляем выводимые разряды
if (count == 2) PORTB |= (1<<2);
if (count == 3) PORTB |= (1<<3);
count++; // включаем следующий разряд
if (count == 4) count = 0;
}
void ADC_result(void)
{
unsigned int adc_tmp;
ADCSRA |= 0x40; //начинаем измерение
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA |=0x10;
adc_tmp=ADCW;
ADC_volt=adc_tmp*4.88;
}
// Обработчик прерывания по переполнению таймера2
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
ind_update();
}
void main(void)
{
PORTB=0x00;
DDRB|=(1<<0)|(1<<1)|(1<<2)|(1<<3); // настройка на выход. 4 разряда
PORTD=0x00;
DDRD=0xFF; // настройка на выход всего порта
ADCSRA = 0x8E; //0b10001110 - предделитель на 64, прерывания разрешены, ADC включён
ADMUX = 0x40; //0b01000000 - AVCC , ACD0, ADLAR off
TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
TCCR2 |= (1 << CS21); // предделитель таймера2 на 8
#asm ("sei") // глобально разрешаем прерывания.
while (1)
{
ADC_result();
data_convert(ADC_volt);
delay_ms(200);
}
}