Нескольно простых вопросов о программировании AVR на Си.

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение WiseLord »

Вот, гляньте на этот код. Как минимум, в Proteus всё работает. Правда, нет защиты от дребезга при отпускании кнопки, но, возможно, она и не нужна при отпускании.
Вложения
buttons.7z
(12.51 КБ) 269 скачиваний
Аватара пользователя
ks0
Прорезались зубы
Сообщения: 230
Зарегистрирован: Чт фев 28, 2013 14:16:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ks0 »

В комментарии?

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

//PORTB=_BV(0);       //включаем лампочку
DrRain
Первый раз сказал Мяу!
Сообщения: 30
Зарегистрирован: Чт янв 01, 2015 18:52:59

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение DrRain »

Для WiseLord Спасибо огромное за код, из hex заработал на макете. буду изучать код, смотреть где накосячил :write:

Для ks0 По моей логике да. Изначально была команда, но подумав я её исключил, т.к. команда на установку этого бита была подана в пред идущем условии, и других команд на отмену не поступало, так что просто сбрасываем флаг и счетчик. Или я чего не правильно понимаю? Я ж тока тока познакомился с C++ :))
Mikhail
Родился
Сообщения: 9
Зарегистрирован: Пт май 04, 2007 22:32:16
Откуда: Великий Новгород
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение Mikhail »

pcb писал(а):лови друх :tea:
http://www.c-cpp.ru/books/inicializaciya-massiva

лень писать, поэтому только так

Чето не понимаю. Сделал все как там написано, все равно ругается.
itak
Родился
Сообщения: 7
Зарегистрирован: Вт дек 04, 2012 09:55:11

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение itak »

Прошу совета, уже голову сломал...

Контроллер упорно не желает выходить из прерывания - преверяю условие внутри функции прерывания, при его выполнении хочу выйти из функции - условие выполняется, контроллер выполняет действия по условию, но из прерывания не выходит, продолжает выполнять функцию обработки до конца.

Вот код функции обработки прерывания:

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

ISR(INT0_vect) // Внешнее прерывания по появлению сигнала
{
   CTR=0; ERR=0; TW=0; HS=0; k=0;
   uint8_t n=0;
   while (n<50)  //цикл ожидания  сигнала
   {
      /*измеряем длительность  импульса*/
      CTR=0;
      while (!(PINB&(1<<PB1)))  //пока сигнал 0 меряем длительность сигнала
      {
         _delay_ms(100);  //делаем задержку
         CTR++;
         if (CTR>=30)          //если сигнал длинный
         {
            n=49;
            break;       //переходи на включение автомата
         }
      }
      if ((CTR>=1) && (CTR<30))     //если сигнал короткий
      {
         k++;     //увеличиваем период счетчик  количества сигналов на 1
         n=0;     // обнуляем период ожидания нажатия сигнала
         if (k>=LOS) // если уже получено 3 сигнала
         {
            /* ручное включение */
            PORTB|=(1<<3); //вкл индикатора
            PORTB&=~(1<<4); //0 на порт РВ4
            delay_s(MLt);
            PORTB|=(1<<4);
            PORTB &= ~_BV(PB3);
            return; //reti(); //выходим из прерывания       
         }
      }
      _delay_ms(100);
      n++;
   }
   for(n=0; n<100; n++){
      PORTB^=(1<<PB3);
      _delay_ms(150);
   }
}
Аватара пользователя
slavokhire5
Прорезались зубы
Сообщения: 202
Зарегистрирован: Пн сен 26, 2011 13:48:25
Откуда: Харьков

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение slavokhire5 »

itak, прочтите раздел Manually defined ISRs отсюда http://www.nongnu.org/avr-libc/user-man ... rupts.html
возможно поможет
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
-=eagle=-
Родился
Сообщения: 7
Зарегистрирован: Сб апр 18, 2015 00:48:07

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение -=eagle=- »

Прошу совета, есть такой код, обработки индикатора и ультразвукового датчика HC-SR04, все работает, но в конце кода, в цикле присутствует "_delay_ms(60);", из-за чего происходит мерцание индикатора, без задержки не вариант! :) Как это обойти? Сильно не пинайте, только учусь)

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

#define  F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile long avg = 0;
volatile unsigned char up = 0;
volatile uint32_t running = 0;
volatile uint32_t timercounter =0;

// Прерывание INT1, для определения изменений высокого/низкого уровня напряжения, to detect high/low voltage changes
ISR(TIMER0_OVF_vect)
{
   if (up) {
      timercounter++;
   }
}

void dig_out(int num); // Объявление функции вывода на индикатор

void send_trigger() //Функция работы с триггером, посылает кратковременный импульс 10us
{
   PORTD = 0x00;
   //_delay_us(5);
   PORTD = 0xf0;
   running = 1;
   _delay_us(10);
   PORTD = 0x00;
}

SIGNAL(INT1_vect){
   if(running){ //прерывания разрешаются, только когда датчик запущен
      if (up == 0) { // voltage rise, start time measurement
         up = 1;
         timercounter = 0;
         TCCR0 |= (0 << CS02)|(0 << CS01)|(1 << CS00); // Start/initialize timer with prescalar 0
         TCNT0 = 0; // Initialize Counter
         } else { // voltage drop, stop time measurement
         up = 0;
         avg = (timercounter*32+TCNT0)/58;// divide by 58 to get distance in cm
         running = 0;
                  
      }
   }
}


void dig_out(int num) // Функция для вывода на индикатор 4-х разрядов
{
   unsigned char i = 0; // Переменная счетчика
   unsigned char raz = 1; // Номер разряда
   unsigned char dig_num[] = {
      0x3f, //0
      0x06, //1
      0x5b, //2
      0x4f, //3
      0x66, //4
      0x6d, //5
      0x7d, //6
      0x07, //7
      0x7f, //8
      0x6f}; // Коды цифр для индикатора с общим катодом
   unsigned char dig[] = {0, 0, 0, 0}; // Массив для значения разряда
   
   if(num < 10) // Для заполнения нулями левых разрядов
      {
         dig[0] =0;
         dig[1] =0;
         dig[2] =0;
      }
   
   if(num < 100) // Для заполнения нулями левых разрядов
      {
         dig[0] =0;
         dig[1] =0;
      }
   
   if(num < 1000) // Для заполнения нулями левых разрядов
      {
         dig[0] =0;
      }
   
   while(num > 999)  // Получение количества тысяч
      {
         dig[0]++;
         num -= 1000;
      }
   
   while(num > 99)  // Получение количества сотен
      {
         dig[1]++;
         num -= 100;
      }
   
   while(num > 9) // Получение числа десятков
      {
         dig[2]++;
         num -= 10;
      }
   
   dig[3] = num; // Получения количества единиц
   
   while(raz <= 0x10) // Крутимся пока не заполним все 4 разряда
      {
         PORTA = raz; // Выбираем разряд
         PORTC = dig_num[dig[i]]; // Выводим цифру
         raz = raz<<1; // Сдвигаемся на следующий разряд
         i++; // Увеличиваем индекс следующей цифры
         _delay_ms(1); // Задержка 1 мс
      }
}

int main(void)
{
   
   DDRA = 0x0F;  // Настройка портов
   DDRC = 0xFF;  // для работы с индикатором Порт A для разрядов, Порт C для цифр
   DDRD = 0xf0; //PD4 вход ECHO, PD5 выход на триггер
   PORTD = 0x00;
      
   MCUCR |= (0 << ISC11) | (1 << ISC10); // enable interrupt on any(rising/droping) edge
   GICR |= (1 << INT1);  //Turns on INT1

   TIMSK |= (1 << TOIE0);  // enable timer interrupt
   
   
   sei(); // Разрешение прерываний
   
      
   
   while(1)
   {
      
         
      dig_out(avg);   //Постоянно вызываем функцию вывода текущего числа
      if(running == 0) {
         _delay_ms(60);
         send_trigger();
                        
      }
      
   }
}
itak
Родился
Сообщения: 7
Зарегистрирован: Вт дек 04, 2012 09:55:11

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение itak »

slavokhire5 писал(а):itak, прочтите раздел Manually defined ISRs отсюда http://www.nongnu.org/avr-libc/user-man ... rupts.html
возможно поможет


Спасибо, пробовал отсюда оператор reti() вместо return - не помогает... Странно, все это...
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение WiseLord »

itak: это где вы такому научились - циклы, стомиллисекундные задержки - и всё это внутри прерывания? Прерывание должно выполняться максимально возможно быстро.

-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.
itak
Родился
Сообщения: 7
Зарегистрирован: Вт дек 04, 2012 09:55:11

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение itak »

WiseLord: - спасибо, направление, подумаю как сделать по другому.

РS в проекте контроллер ничего не делает (спит) до наступления события. Задержки минутные. Интервалы между событиями часы. В Proteus программа работает....

я только учусь (это мой второй проект).
-=eagle=-
Родился
Сообщения: 7
Зарегистрирован: Сб апр 18, 2015 00:48:07

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение -=eagle=- »

WiseLord писал(а):
-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.


Сделал по таймеру сравнения, все заработало, но не совсем корректно, показания с датчика чудят при определенный настройках, а когда не чудит. индикатор мерцает, никак не совместить эти моменты, не пойму как грамотно его настроить :(

Спойлер

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

#define  F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile long avg = 0;
volatile long result = 1234;
volatile unsigned char up = 0;
volatile uint32_t running = 0;
volatile uint32_t timercounter =0;

// Прерывание INT1, для определения изменений высокого/низкого уровня напряжения, to detect high/low voltage changes
ISR(TIMER0_OVF_vect)
{
   if (up) {
      timercounter++;
   }
}

void dig_out(int num); // Объявление функции вывода на индикатор

void send_trigger() //Функция работы с триггером, посылает кратковременный импульс 10us
{
   PORTD = 0x00;
   //_delay_us(5);
   PORTD = 0xf0;
   running = 1;
   _delay_us(10);
   PORTD = 0x00;
}

SIGNAL(INT1_vect){
   if(running){ //прерывания разрешаются, только когда датчик запущен
      if (up == 0) { // voltage rise, start time measurement
         up = 1;
         timercounter = 0;
         TCCR0 |= (0 << CS02)|(0 << CS01)|(1 << CS00); // Start/initialize timer with prescalar 0
         TCNT0 = 0; // Initialize Counter
         } else { // voltage drop, stop time measurement
         up = 0;
         avg = (timercounter*32+TCNT0)/58;// divide by 58 to get distance in cm
         running = 0;
         
                  
      }
   }
}




   
   
/*******************************************/

ISR (TIMER1_COMPA_vect)  // Обработчик прерывания по совпадению таймера 1
{
   dig_out(avg);   //Постоянно вызываем функцию вывода текущего числа
   TCNT1H=0x00; // Сброс регистра
   TCNT1L=0x00; // счета
      
   
}




void dig_out(int num) // Функция для вывода на индикатор 4-х разрядов
{
   unsigned char i = 0; // Переменная счетчика
   unsigned char raz = 1; // Номер разряда
   unsigned char dig_num[] = {
      0x3f, //0
      0x06, //1
      0x5b, //2
      0x4f, //3
      0x66, //4
      0x6d, //5
      0x7d, //6
      0x07, //7
      0x7f, //8
      0x6f}; // Коды цифр для индикатора с общим катодом
   unsigned char dig[] = {0, 0, 0, 0}; // Массив для значения разряда
   
   if(num < 10) // Для заполнения нулями левых разрядов
      {
         dig[0] =0;
         dig[1] =0;
         dig[2] =0;
      }
   
   if(num < 100) // Для заполнения нулями левых разрядов
      {
         dig[0] =0;
         dig[1] =0;
      }
   
   if(num < 1000) // Для заполнения нулями левых разрядов
      {
         dig[0] =0;
      }
   
   while(num > 999)  // Получение количества тысяч
      {
         dig[0]++;
         num -= 1000;
      }
   
   while(num > 99)  // Получение количества сотен
      {
         dig[1]++;
         num -= 100;
      }
   
   while(num > 9) // Получение числа десятков
      {
         dig[2]++;
         num -= 10;
      }
   
   dig[3] = num; // Получения количества единиц
   
   while(raz <= 0x10) // Крутимся пока не заполним все 4 разряда
      {
         PORTA = raz; // Выбираем разряд
         PORTC = dig_num[dig[i]]; // Выводим цифру
         raz = raz<<1; // Сдвигаемся на следующий разряд
         i++; // Увеличиваем индекс следующей цифры
         _delay_ms(1); // Задержка 1 мс
      }
}

int main(void)
{
   
   DDRA = 0x0F;  // Настройка портов
   DDRC = 0xFF;  // для работы с индикатором Порт A для разрядов, Порт C для цифр
   DDRD = 0xF0; //PD4 вход ECHO, PD5 выход на триггер
   PORTD = 0x00;
   
   TCCR1A=0x00; // Настройка таймера
   TCCR1B = (0 << CS12)|(0 << CS11)|(1 << CS10);
   TCNT1H=0x00;
   TCNT1L=0x00;
   OCR1AH=0x04;
   OCR1AL=0x05;
   
   
   
   MCUCR |= (0 << ISC11) | (1 << ISC10); // enable interrupt on any(rising/droping) edge
   GICR |= (1 << INT1);  //Turns on INT1

   TIMSK |= (1 << TOIE0)|(1 << OCIE1A);  // enable timer interrupt
   
   
   sei(); // Разрешение прерываний
   
      
   
   while(1)
   {
   
      if(running == 0) {
         _delay_ms(60);
         send_trigger();
                        
      }
            
   }
}
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

Есть проблема с таким кодом:
Спойлер

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

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL

volatile unsigned char input_bits;  //буфер команды
unsigned char control_bits;  //команда

void main(void)
{
  //инициализация UART
  //удвоение скорости обмена отключено, мультипроцессорный обмен отключен
  UCSRA &= ~((1 << U2X) | (1 << MPCM));
  //разрешение прерывания по завершению приема, работы порта PD0 на прием
  UCSRB |= (1 << RXCIE) | (1 << RXEN);
  //запись в UCSRC, асинхронный режим, контроль четности отключен,
  //один стоп-бит, 8-разрядное слово
  UCSRC |= (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
  //скорость передачи 9600 bps по формуле fck/(16*(speed+1))
  UBRRL = 51;
 
  //инициализация выходов
  //выхода индикации
  DDRB |= 0xFF;

  sei();

  while(1)
  {
    control_bits = input_bits;

    //индикация команды
    PORTB = control_bits;
  };
}

//вектор прерывания по окончанию приема байта
ISR(USART_RXC_vect)
{
  while (UCSRA & (1 << RXC))
    input_bits = UDR;
}

Это я пытаюсь считать 8-бит данных через аппаратный USART контроллера Atmega8 и выдать их на порт Б. Вроде как логика простая: включаю прерывание по окончанию приема, считываю данные из регистра UDR, пока флаг окончания приема не сбросится, передаю данные в другую переменную и вывожу ее на порт. Но не работает. На выводах порта какая-то чушь. Проверяю в Протеусе, тот при этом выдает сообщение RX Frame Error. Кажется, я туплю в понимании методики приема. Подскажите. куда копать?
We do what we must because we can (c) GLaDOS
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ARV »

не понятно, нафига все эти переменные и прерывание, когда вы можете просто делать в главном цикле

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

while(UCSRA & _BV(RXC)) PORTB = UDR;
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

С прерыванием оно как-то красивше. Получили пакет, тут же засунули его в переменную, которую можно потом обработать как душе угодно. Всегда свежие данные есть. В вашем случае данные получаем только один раз за рабочий цикл программы, независимо от того, сколько раз они обновились. Если просто индицировать, оно вроде как и рационально, но я потом планирую еще с этими данными работать.

Вопрос не в этом. Должно же работать и с прерыванием. А оно почему то никак.
We do what we must because we can (c) GLaDOS
Аватара пользователя
ks0
Прорезались зубы
Сообщения: 230
Зарегистрирован: Чт фев 28, 2013 14:16:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ks0 »

А че там за ожидание в прерывании? Обработчик же и так при наступлении события вызывается?
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

В прерывании ожидание сброса флага RXC. В интернетах пишут, что он может не сбросится после первого чтения из UDR, потому читаем до победного, пока не сбросится. Сегодня ковыряться некогда было, завтра попробую без прерываний самый простой вариант, но, кажется, дело не в том.
We do what we must because we can (c) GLaDOS
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

Такой появился вопрос. Если у меня постоянно на вход UART приходят пакеты, то как определяется, где начало, где конец? На картинке пример. Когда приходят нули, все понятно. А когда не ноль, то за стоп/старт-биты может быть принято любое последовательное сочетание 1 и 0. Как этот вопрос разрешается при использовании аппаратного асинхронного UART для пары котнроллеров (передатчик-приемник)?
Изображение
We do what we must because we can (c) GLaDOS
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение Jack_A »

Стоп-бит фиксируется не по любому переходу из низкого в высокий. Получив стартовый бит, автомат USARTа отмеривает время, необходимое для передачи заданного количества бит, включая стартовый, на заданной скорости, после чего проверяет состояние RxD . Если высокий, байт считается принятым, аппарат готов к приему следующего. Если низкий - FRAME ERROR . Поэтому важно, чтобы приемник UART был настроен в соответствии с передаваемыми данными : число бит ( инф. и стоповых ), скорость передачи. Иначе - FRAME ERROR, если его игнорировать, читаем абракадабру.
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

Со стопом понятно. Но старт-битом ведь считается любой переход от 1 к 0. Контроллеры не синхронизированны по частоте, и в какой момент (имеется в виду начальный, при включении питания контроллеров) начнется передача на передатчике и прием на приемнике (жуть какая) не ясно. Т.е. приемник может включиться на прием чуть позже и считать переход от второго бита на третий как переход стоп-старт (см. рисунок выше). Или это как-то не так работает?
We do what we must because we can (c) GLaDOS
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение Аlex »

baron_P писал(а):Т.е. приемник может включиться на прием чуть позже
Это как ?
Он включится ровно тогда, когда ему об этом скажут. Как Вы только настроили приёмник, он сразу готов принимать.
Ответить

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