Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
10.08.2011, 10:30
|
|
Частый гость
Регистрация: 01.11.2007
Сообщений: 27
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Странный глюк с sprinf, помогите разобраться
Здравствуйте! Собрал разрядное устройство для аккомуляторов, как напряжение упадет ниже 0.9в разряд отключаеться. На экран циклически выводиться информация о напряжении и отданной емкости на разряд. Каждые 3 секунды меняеться информация на LCD. При каждой смене ощущение что переменные u1,u2,u3,u4,c1,c2,c3,c4 обнуляються. Причем происходит во время команды
"sprintf(str1,"v1=%-.2f v2=%-.2f\nv3=%-.2f v4=%-.2f",u1,u2,u3,u4);"
"sprintf(str1,"c1=%-.2f c2=%-.2f\nc3=%-.2f c4=%-.2f",c1/1000,c2/1000,c3/1000,c4/1000);"
Что я делаю не так? Код программы прилагаю ниже:
/*******************************/
/* Подключим библиотеку контроллера */
# include "mega8.h"
# include "delay.h"
# include "stdio.h"
/* Объявим порт подключения LCD */
#asm
.equ __lcd_port=0x12
#endasm
/*Библиотека LCD*/
# include "lcd.h"
char str1[16];
float u1;
float u2;
float u3;
float u4;
float c1;
float c2;
float c3;
float c4;
float set;
float resist;
int f1;
int f2;
int f3;
int f4;
int count;
bit cap;
void test()//Тест
{
DDRB=0xFF;//Порт В на выход
PORTB=0x00;//Выключить все реле
sprintf(str1," auto test...");
lcd_init(16);
lcd_puts(str1);
PORTB=0x00;
delay_ms(500);
PORTB=0x00;
PORTB.0=1;
delay_ms(500);
PORTB=0x00;
PORTB.1=1;
delay_ms(500);
PORTB=0x00;
PORTB.2=1;
delay_ms(500);
PORTB=0x00;
PORTB.3=1;
delay_ms(500);
PORTB.0=1;
PORTB.1=1;
PORTB.2=1;
PORTB.3=1;
delay_ms(500);
PORTB=0x00;
sprintf(str1," starting ");
lcd_init(16);
lcd_puts(str1);
delay_ms(500);
}
/*Вывод напряжения на на LCD*/
void dispu(void)
{
lcd_clear();
sprintf(str1,"v1=%-.2f v2=%-.2f\nv3=%-.2f v4=%-.2f",u1,u2,u3,u4);
lcd_puts(str1);
}
/*Вывод емкость на на LCD*/
void dispc(void)
{
lcd_clear();
sprintf(str1,"c1=%-.2f c2=%-.2f\nc3=%-.2f c4=%-.2f",c1/1000,c2/1000,c3/1000,c4/1000);
lcd_puts(str1);
}
//Настройка таймера//
void tm_init()
{
ASSR|=0x08; // Тактировать T2 от асинхронного генератора таймера, установка бита AS2 в регистре assr
TCCR2|=0x05;//делим на 128 такт кварца
TIMSK|=0x40;//Включаем прерываение по переполнению таймера 2
}
/* ADC */
/* Инициализация */
void ADC_init()
{
ADMUX=0xE0;
ADCSRA=0x8D;
}
/* Преобразование */
float ADC_result(unsigned char adc_input)
{
ADC_init();
ADMUX=adc_input|(ADMUX & 0xFF);
delay_ms(10);
/*Старт преобразования */
ADCSRA|=0x40;
while((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCH*0.01;
}
//Установка битов порта В
void port()
{
if (u1›set) {if (f1==0){PORTB.3=1;}}
if (u1‹set) {f1=1; PORTB.3=0;};
if (u1‹0.1) {f1=0; c1=0; PORTB.3=0;};
if (u2›set) {if (f2==0){PORTB.2=1;}}
if (u2‹set) {f2=1; PORTB.2=0;};
if (u2‹0.1) {f2=0; c2=0; PORTB.2=0;};
if (u3›set) {if (f3==0){PORTB.1=1;}}
if (u3‹set) {f3=1; PORTB.1=0;};
if (u3‹0.1) {f3=0; c3=0; PORTB.1=0;};
if (u4›set) {if (f4==0){PORTB.0=1;}}
if (u4‹set) {f4=1; PORTB.0=0;};
if (u4‹0.1) {f4=0; c4=0; PORTB.0=0;};
}
interrupt [TIM2_OVF] void timer2_ovf_isr(void)//Прерывание по таймеру 2
{
#asm("cli")
u1=ADC_result(0x00);//Измерение напряжения
u2=ADC_result(0x01);
u3=ADC_result(0x02);
u4=ADC_result(0x03);
//Расчет емкости
c1=c1+(u1/resist)*0.2777777;//ma*час
c2=c2+(u1/resist)*0.2777777;
c3=c3+(u1/resist)*0.2777777;
c4=c4+(u1/resist)*0.2777777;
count++;
if (count›3) {
if (cap==0) {dispu();};//Показ напряжения
if (cap==1) {dispc();}; //Показ емкости
cap=cap^1;//инверсия бита показа
count=0;
}
PORTC.4=PORTC.4^1;//Мигаем диодом
port();//Переключаем реле
#asm("sei")//иначе не работает задержка
}
/*Основная программа */
void main(void)
{
test();//Тест реле 3 секунды
DDRC|=0x10;//Установить порт РС4 на Выход мигалка
PORTC.4=0;;//Установить на порту РС4 1
tm_init();//Запуск таймера и прерываний
set=0.9;//Напряжение окончания разряда
f1=0;f2=0;f3=0;f4=0;//Сброс флагов состояния каналов
resist=1;//сопротивление в цепи разряда
count=3;//через сколько секунд будет смена показа на LCD
#asm("sei")//для дальнейшей работы по таймеру
while(1)
{
}
}
|
|
|
Сказали "Спасибо" tarasov128
|
|
|
10.08.2011, 11:36
|
|
Гражданин KAZUS.RU
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
|
Re: Странный глюк с sprinf, помогите разобраться
Честно говоря, немного поднадоело повторять прописные истины ... Вы их похоже всё равно не читаете...
1. Прерывание на то и прерывание, чтобы быть максимально коротким.
2. Всякие sprintf - это самые тяжеловесные библиотеки. Которые занимают максимум времени и кучу стэка. Надо применять их крайне осторожно.
3. Сам вывод в LCD - крайне медленная операция в связи с тем, что приходится формировать временную диаграму работы с дисплеем.
4. НИКОГДА не всовывайте операторы не понимая причины неработоспособности. Вы просто маскируете ошибку но не устраняете её. При неработоспособности нужно разобраться и найти ошибку, а не тыкать куда попало пальцем.
===
Теперь касаемо вашего проекта... В конце прерывания у вас стоит "#asm("sei")//иначе не работает задержка". Это бессмысленный оператор, так как по выходу из прерывания процессор сам, аппаратно, разрешит прерывания. Таким образом, если бы у вас всё было правильно, то данная строчка не дала бы не малейшего результата. Отсюда следует, что скорее всего, ваше прерывание не успевает выполнится за время ему отведённое. Оно и понятно, вы в него впёрли неизвестно что... Соответственно, когда вы ставите разрешение прерывания вы скорее всего разрешаете повторный вход в прерывание. У вас скорее всего плывёт стек и происходит крах программы с последующим перезапуском. Поведение такой программы предсказать невозможно. Оно будет меняться при любом изменении текста программы. От компиляции к компиляции.
===
Вам необходимо выкинуть ненужное... вынести из прерывания вывод в голову либо в разы увеличить время между прерываниями.
|
|
|
Сказали "Спасибо" SasaVitebsk
|
|
|
10.08.2011, 11:58
|
|
Частый гость
Регистрация: 01.11.2007
Сообщений: 27
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: Странный глюк с sprinf, помогите разобраться
1. Контроллер успевает выполнить код внутри прерывания, прерывания раз в секунду происходят.
2. Sprintf работает, если просто выводить текст на экран и использовать форматирование и переменные.
3.Прерывания разрешаю, потому-что сам запрещал их, и не знал что потом автоматически они будут разрешены. Вреда от строчки не вижу.
4. Памяти конкретно на эту программу у 8й меги хватает, и краха стека не происходит, если бы процессор повис или ушел в reset я бы увидел это на устройстве.
Расскажите почему так странно переменные меняються(надеюсь дело вних)? Или расскажите пример вывода без sprintf, я мало работал с CodeVision и вообще с контроллерами, это всего мой второй проект, не ругайте сильно)
Я понимаю, что если помучаюсь, могу уйти от sprintf, но почему оно как уже написано не работает?
|
|
|
Сказали "Спасибо" tarasov128
|
|
|
10.08.2011, 12:24
|
|
Прописка
Регистрация: 25.09.2009
Адрес: Ivanovo
Сообщений: 156
Сказал спасибо: 3
Сказали Спасибо 67 раз(а) в 60 сообщении(ях)
|
Re: Странный глюк с sprinf, помогите разобраться
Обявите перем. как volatile может оптимизатор чего косячит. И на счет времени входа в прер. проверте еще раз. На всякий...
|
|
|
Сказали "Спасибо" heady69
|
|
|
10.08.2011, 12:46
|
|
Частый гость
Регистрация: 01.11.2007
Сообщений: 27
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: Странный глюк с sprinf, помогите разобраться
Извините, разобрался, кривизна рук виновата. Исправил char str1[16]; на char str1[32]; с все заработало...)))
|
|
|
Сказали "Спасибо" tarasov128
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 20:53.
|
|