Программа работает в proteus'e но на железе отказывается

Обсуждаем контроллеры компании Atmel.
Ответить
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

День добрый, ломал голову как сделать счетчик от 0 до 99 с обнуление при переполнении. Вроде бы сломал и сделал, через прерывания, таймер и все такое. Проверил в протеусе работает. Стал проверять на железе высвечиваются по 0 на обоих сегментах :( думал мк закосячил, залил старую программку для вывода чисел указанных в коде - все нормально вывело, а тут не считает. Делал по урокам в инете, все в кучу собрал но не повезло. В протеусе адекватно работает на частоте в 2МГЦ, в реале перепробовал все частоты внутреннего генератора от 1-2-4-8 на всех высвечивается по 00 :(
Может быть кто подскажет что не так в коде? Подключение на макетке правильно ибо если было бы не правильно прошлые программы не работали бы.
сделано в CVAVR код и схему прилагаю, а так же проект+протеус.
Код программы:
Спойлер

Код: Выделить всё

#include <mega8.h>
#include <delay.h>


static flash unsigned char digit[] = {
         ~(0b00111111),       // 0
         ~(0b00000110),       // 1
         ~(0b01011011),       // 2
         ~(0b01001111),       // 3
         ~(0b01100110),       // 4
         ~(0b01101101),       // 5
         ~(0b01111101),       // 6
         ~(0b00000111),       // 7
         ~(0b01111111),       // 8
         ~(0b01101111),       // 9
};
////
unsigned char sek;
bit m;
////
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
TCNT2=0b00000000;  //счетный регистр 0-255
sek++;
if(sek>=100) {
sek=0;}
}
  //вывод на индикатор
void ind(unsigned char chislo)
{
unsigned char des=0;
while(chislo>=10){
chislo-=10;     //вычитаем и присваиваем заново
des++;}

if(m==0){
PORTB.0=1;
PORTD=digit[des];
delay_ms(5);
PORTB.0=0;
PORTB.1=1;
PORTD=digit[chislo];
delay_ms(5);
PORTB.1=0;}
}
//////////////
void main (void){
PORTB=0b00000000;
DDRB= 0b00000011;

PORTD=0b00000000;
DDRD= 0b01111111;

    //настройки 2 таймера и его прерываний
ASSR= 0b00001000;
TCCR2=0b00000110; //деление  32768 на 256
TCNT2=0b00000000;  //счетный регистр 0-255
OCR2=127;  //регистр сравнения
TIMSK=0b10000000;

#asm("sei");   //разрешение глобавльных прерываний
/////////////////////////////////////////
while (1){ind(sek);}
}
Схема:
СпойлерИзображение
Архив с проектом и схемой в протеусе:
проект.rar
(65.41 КБ) 261 скачивание
Реклама
Вымогатель припоя
Сообщения: 532
Зарегистрирован: Вт фев 09, 2010 17:52:26

Сообщение codenamehawk »

Код: Выделить всё

if(m==0){
Лишний кусок кода.

Код: Выделить всё

unsigned char sek;
Попробуйте заменить на.

Код: Выделить всё

voliatile unsigned char sek;
Ваша программа, если работает в Протеусе, должна работат и в проце.
Возмозно в проце выставлена работа от внешнего кварца.
Реклама
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

codenamehawk писал(а):Возмозно в проце выставлена работа от внешнего кварца.
Сделал как вы сказали, в протеусе работает на железе опять нет. Фьюзы стоял на внутренний кварц 8МГц если я не ошибаюсь. Вот скриншот как выставлены фьюз-биты
СпойлерИзображение
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

Поставь студию попроще, к примеру 4.19, файл .cof в отладчик.
Реклама
Эиком - электронные компоненты и радиодетали
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Порт B то у Вас явно перегружен.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

Vov123 писал(а):Поставь студию попроще, к примеру 4.19, файл .cof в отладчик.
а где взять этот файл и как туда запихать?
Z_h_e писал(а):Порт B то у Вас явно перегружен.
а как его собственно разгрузить? на нем же только 2 анода сегментов висят и все...
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

moonlight1 писал(а):а как его собственно разгрузить? на нем же только 2 анода сегментов висят и все...
А Вы посчитайте какой ток будет, если зажечь все сегменты. Аноды говорите... поставте биполярный NPN транзистор. База на порт, коллектор на + питания, эмиттер на анод.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

Z_h_e писал(а):
moonlight1 писал(а):а как его собственно разгрузить? на нем же только 2 анода сегментов висят и все...
А Вы посчитайте какой ток будет, если зажечь все сегменты. Аноды говорите... поставте биполярный NPN транзистор. База на порт, коллектор на + питания, эмиттер на анод.
без этого вполне на другой программе работает.
вот в этой программе, счет от 0 до 999 по нажатию кнопки, все нормально работает на железе
Спойлер

Код: Выделить всё

#define F_CPU 8000000UL //выбор частоты тактирования (8Мгц)
#include <mega8.h>
#include <delay.h>

unsigned char number[] = 
{
  ~0x3f, //0
  ~0x06, //1
  ~0x5b, //2
  ~0x4f, //3   
  ~0x66, //4
  ~0x6d, //5 
  ~0x7d, //6
  ~0x07, //7   
  ~0x7f, //8
  ~0x6f  //9    
};

unsigned char count = 0;

//числа для вывода на индикатор
unsigned char data1 = 9;
unsigned char data2 = 9;
unsigned char data3 = 5;

void main( void )
{
  //порт, к которому подкл. сегменты
  PORTD = 0xff;
  DDRD = 0xff;
  
  //порт, к которому подкл. анод
  PORTB = 0;
  DDRB = (1<<0)|(1<<1)|(1<<2); 
  
  while(1)
  {
    //гасим все разряды
    PORTB &= ~((1<<0)|(1<<1)|(1<<2));
    
    //зажигаем следующий разряд
    if (count == 0) {
      PORTD = number[data1];
      PORTB |= (1<<0); 
    }
    if (count == 1) {
      PORTD = number[data2];
      PORTB |= (1<<1);}
      if (count == 2) {
      PORTD = number[data3];
      PORTB |= (1<<2);
    }  
    
    //типо кнопка
 if (PINB.3==0) 
    {   delay_ms(200);   //типо антидребезг 
    data3++;
     } 
    //счет 0-999
    while(data3>=10){
    data3-=10;
    data2++;}
    while(data2>=10){
    data2-=10;
    data1++;}
         if(data1==10) {data1=0; data2=0; data3=0;} 
         
    count++;
    if (count == 3) count = 0;
    delay_ms(10); 
    
     
  }  
}
схема
СпойлерИзображение
в реали к сожалению нет у меня транзистора нпн, но без него с другим кодом работает, а с тем что в 1м сообщении нет. не думаю что купив транзисторы заработает, но попытаться стоит ;)
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Да я и не говорил что у Вас нули показывает из-за перегрузки порта.

Попробуйте функцию ind вызывать редко, например раз 3 сек и используйте в параметре не переменную, а некое число. Может увидите, что у Вас происходит и локализуете проблему.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

Z_h_e писал(а):Да я и не говорил что у Вас нули показывает из-за перегрузки порта.

Попробуйте функцию ind вызывать редко, например раз 3 сек и используйте в параметре не переменную, а некое число. Может увидите, что у Вас происходит и локализуете проблему.
а) ну значит я не так понял. попробую спасибо
попробовал, вызывать реже, чет все равно тоже самое =\
ладно черт с ней, потом додумаю может быть почему не работает.
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Фьюзы стоял на внутренний кварц 8МГц
Где вы нашли контроллер с внутренним кварцем? Явно ведь не ATmega8, у нее встроенного кварца нет, только RC-генератор.
static flash unsigned char digit[] = {
~(0b00111111), // 0
Не самый удобный способ записи. Хотя в вашем примере на 999, эта инициализация реализована еще хуже.
PORTB.0=1;
PORTD=digit[des];
delay_ms(5);
В cvavr не надо делать ручное чтение из flash? В avr-gcc для этого pgm_read_byte() и т.п.
Можно попробовать увеличить задержку здесь.
ASSR= 0b00001000;
Форматирование ужасно. Какая религия мешает писать по-человечески? Запретите ее на форуме. ASSR = (1<<AS2);
Сам асинхронный таймер тактируется? Попробуйте помигать диодами из его прерывания или затактировать от системного таймера. Кстати, на схеме низкочастотного кварца нет.
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

COKPOWEHEU писал(а):только RC-генератор.
я это и умел ввиду :oops:
Не самый удобный способ записи. Хотя в вашем примере на 999, эта инициализация реализована еще хуже.
как смог так сделал. не все же сразу должно быть хорошо :)
Сам асинхронный таймер тактируется? Попробуйте помигать диодами из его прерывания или затактировать от системного таймера. Кстати, на схеме низкочастотного кварца нет.
хорошо. спасибо
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Код: Выделить всё

#define SEG_PORT PORTD
#define SEG_A 0
#define SEG_B 1
...
#define SEG_F 5
#define SEG_G 6
PROGMEM const char num[]={
  ~(1<<SEG_A | 1<<SEG_B | 1<<SEG_C | 1<<SEG_D | 1<<SEG_E | 1<<SEG_F), //0
  ~(1<<SEG_B | 1<<SEG_C), //1
...
  ~(1<<SEG_A | 1<<SEG_B | 1<<SEG_C | 1<<SEG_D | 1<<SEG_E | 1<<SEG_F | 1<<SEG_G), //8
  ~(1<<SEG_A | 1<<SEG_B | 1<<SEG_C | 1<<SEG_D | 1<<SEG_F | 1<<SEG_G) //9
};
Такой способ позволяет легко менять выводы местами, плюс этот кусок можно таскать из кода в код. Ну и выглядит нагляднее, чем "магические числа".
как смог так сделал. не все же сразу должно быть хорошо :)
Когда я делаю динамическую индикацию, обычно завожу "видеобуфер" и отрисовываю его по таймеру.

Код: Выделить всё

#define DIG_PORT PORTB
#define DIG_MASK (1<<0 | 1<<1)
const char digits[2]={
  (1<<0),
  (1<<1)
};

volatile char video_buf[2];

//динамическая индикация
ISR(TIM0_OVF_vect){
  static unsigned char digit=0;
  DIG_PORT &=~DIG_MASK; //перед переключением обязательно надо погасить предыдущий разряд
  SEG_PORT = video_buf[ digit ];
  DIG_PORT |= digits[ digit ];
  digit++;
  if(digit > 1)digit = 0; //знаю, что можно обойтись инверсией младшего бита, но этот вариант проще масштабировать
}

//вывод целого числа (0-99)
void OutInt(unsigned char data){
  char dec;
  while(data > 10){
    dec++;
    data -= 10;
  }
  video_buf[1] = pgm_read_byte( &num[ dec ] );
  video_buf[0] = pgm_read_byte( &num[ data ] );
}
Примерно так. Писал из головы под avr-gcc, но суть должна быть понятна.
Открыл глаза
Сообщения: 62
Зарегистрирован: Вс июн 28, 2015 18:07:39
Откуда: Алтайский край, город Бийск

Сообщение moonlight1 »

COKPOWEHEU писал(а):легко менять выводы местами
т.е. не важно как будут подключены выводы к мк? круто если так.
все понял в чем соль, не надо считать по битам легко прикинуть как будет.
Когда я делаю динамическую индикацию, обычно завожу "видеобуфер" и отрисовываю его по таймеру.
Примерно так. Писал из головы под avr-gcc, но суть должна быть понятна.
подкинули вы мне пищу для размышлений, освобожусь от дел насущных обязательно буду пробовать
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Преимущество в том, что в пределах одного порта можно вешать сегменты на произвольные пины. Часто у контроллеров выводы одного порта сгруппированы рядом (к сожалению, не всегда, классическая ATmega8 примером), а сегменты у индикатора расположены в произвольном порядке (наверное, какая-то логика в их расположении есть, но я ее не увидел). Тогда для упрощения разводки платы можно поменять местами какие-нибудь выводы.
Несложно сделать и полностью произвольный доступ к каждому выводу, но на мой взгляд это проигрыш по скорости.
подкинули вы мне пищу для размышлений, освобожусь от дел насущных обязательно буду пробовать
Это радует
Родился
Сообщения: 1
Зарегистрирован: Ср авг 08, 2018 20:50:08

Сообщение Владимир-32 »

Здравствуйте, коты, кошечки и котята!
Хочу поделиться некоторым опытом. Написал я программу для Атмеги8 на ассемблере. Программа не очень чтобы сложная, но для меня, как в некоторой степени начинающего пользователя АВРов, довольно сложная и запутанная. Отладил её в Протеусе. Работает отлично! Записал код в микруху, запустил на макетной платке. Не работает! Начал ковырять. Перечитал много тем на разных форумах о причинах неработы программы в железе. Сначала думал, что помехи по питанию. Поставил соответствующие кондёры. Безрезультатно. Потом начал ковырять фьюзы. Дело в том, что раньше когда-то я имел дело с АТ89S52, а там фьюзов нет. Перепробовал разные варианты. Безрезультатно. Думаю, пойду другим путём. Урезал программу до минимума и начал проверять её работу в железе, постепенно добавляя блоки. Вначале всё работало отлично, но после добавления одного из блоков стало происходить странное. Программа то работала, то не работала. Иногда при включении питания или сбросе работала несколько раз подряд, а иногда - по несколько раз подряд не работала. И ещё: если программа не отработала до конца, а я подавал сигнал сброса, то после этого сброса она переставала работать. Знатоки, вероятно, уже поняли причину такого поведения. А мне пришлось повозиться, прежде чем я понял причину, хотя тоже мог бы догадаться.
Теперь о том, как я искал причину.
В некоторых блоках программы поставил команды, которые выводили в свободный порт какое-то число, которое соответствовало порядку выполнения программы. Т. е., если в порту появляется это число, это значит, что программа зашла в своей работе в этот блок. По этому признаку можно определить, что происходит в программе. Но как определить, что это число появляется в порту, ведь программа выполняется довольно быстро? Для этого я использовал 2-канальный цифровой осциллограф в ждущем режиме. Один вход подсоединил на линию порта 0, от неё же брал синхронизацию. А второй вход подключал к остальным выводам порта. Зарисовывал графики. Получилось нечто вроде картины логического анализатора. Совместив графики и проанализировав их, я узнал, куда, в какие блоки заходит программа. Получилось, что программа не заходила в один блок, в который она должна была обязательно зайти. Проанализировав код, я предположил причину, по которой программа не заходит в этот блок. Устранив причину, я добился того, что программа заработала так, как надо!
В чём же была причина?
Причина очень проста. Дойдя до определённого момента, программа анализировала флаг (бит в регистре), который в начале программы должен был быть сброшенным, т. е. равняться 0. Зная, что после команды сброса, МК обнуляет все РОНы, я не позаботился его принудительно обнулить. Оказывается, что МК не обнуляет РОНы при сбросе и включении питания! Это для меня было новостью. МК, с которыми я ранее имел дело, обнуляли все РОНы при сбросе и включении питания. Оказывается, к Атмеге8 это правило не относится. А может быть, схема сброса у меня была не лучшего качества, хотя я перепробовал разные варианты, которые не дали желаемого результата.
Конечно, взрослые жирные коты, наверно, посмеются, что, мол, кот таких простых вещей не знает. Но молодым котятам может пригодиться опыт, который я приобрёл ценой нескольких дней ковыряния в коде программы, поиска схожей причины на форумах и тыкания деталек в макетку. И я буду рад, если мой пост кому-то сэкономит часы, а то и дни поиска неисправности.
Собутыльник Кота
Аватара пользователя
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Сообщение B@R5uk »

Инициализировать нужно всё, чем собираешься пользоваться. Это каждый программист знает. Даже если в даташите пишут, что при ресете регистр ввода-вывода инициализируется каким-либо значением, то это утверждение всегда лучше поставить под сомнение и проинициализировать регистр самостоятельно. У меня была забавная ситуация с ATmega128, когда USART работал не с той скоростью, а всё потому, что я поленился проинициализировать бит, задающий удвоение частоты, из-за того, что он мол по ресету сам устанавливается в нужное значение.
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

B@R5uk писал(а):Даже если в даташите пишут, что при ресете регистр ввода-вывода инициализируется каким-либо значением, то это утверждение всегда лучше поставить под сомнение
Что за чушь?

Добавлено after 12 minutes 14 seconds:
Владимир-32 писал(а):Оказывается, что МК не обнуляет РОНы при сбросе и включении питания! Это для меня было новостью. МК, с которыми я ранее имел дело, обнуляли все РОНы при сбросе и включении питания. Оказывается, к Атмеге8 это правило не относится. А может быть, схема сброса у меня была не лучшего качества, хотя я перепробовал разные варианты, которые не дали желаемого результата.
А где написано что должны были сбрасываться?
На счет поиска ошибки + Вам, тут часто бывает так, код напишут - не работает, ничего не попробовав бегут сразу за помощью.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Собутыльник Кота
Аватара пользователя
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Сообщение B@R5uk »

Z_h_e, мне по чём знать? Спросите разработчиков и производителей. Может очетпятка в документе, ноль и единицу перепутали, а может баг при производстве был, не к той линии питания развели. Мне главное чтобы работало без излишнего мозгосношения, поэтому сомневаюсь во всём и не верю никому на слово.
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Если бы контроллер не инициализировал РВВ так как написано, он бы не работал в принципе.

Если Вам попался неисправный МК, то никакие "правила сделать на всякий случай которые все программисты знают" не помогут.
Если есть такой явный баг, он по-любому будет описан в erratа или в свежем ДШ.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Ответить

Вернуться в «AVR»