UART ATmega8

Обсуждаем контроллеры компании Atmel.
Gin87
Открыл глаза
Сообщения: 74
Зарегистрирован: Вс янв 24, 2010 21:29:07

UART ATmega8

Сообщение Gin87 »

Всем привет! Возможно у кого-то есть код. Помогите пожалуйста.

Суть вот в чем. Нужно передавать числа из терминала в МК. Например 5000 или 125000. Понятно, что терминал будет передавать по одной цифре, побайтно. Конец строки будет определять символ "," (запятая).

Принимать один байт получается. А вот принять побайтно в буфер, получить строку, где запятая конец строки, а потом преобразовать в число не получается.

Пишу на С в AVR Studio 4.

Кто чем может :))

P.S. Да в инете есть примеры, но часто куски вырванные и в общую картину сложить не получается. Переменные пропущены. К тому избыточность тоже не нужна, всякие там кольцевые буферы и прочее.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: UART ATmega8

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

Gin87 писал(а):Возможно у кого-то есть код
Вряд ли у кого-то будет такой специфический код.

Gin87 писал(а):не получается.
Пишу на С в AVR Studio 4.
Что не получается конкретно ? Показывайте.

Конец строки будет определять символ "," (запятая).
Вообще, конец строки определяется нулевым символом ('\0'). Почему у Вас запятая - :dont_know:
Gin87
Открыл глаза
Сообщения: 74
Зарегистрирован: Вс янв 24, 2010 21:29:07

Re: UART ATmega8

Сообщение Gin87 »

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

#ifndef F_CPU
#define F_CPU 7372800UL   //   рабочая частота
#endif

#include <avr/io.h>
#include <util/delay.h>      //   для _delay_ms()
#include <avr/interrupt.h>

volatile unsigned long t=0;
volatile unsigned int v=0;



int init_UART(void)
{
   //   Установка скорости 9600
   UBRRH=0;   //   UBRR=f/(16*band)-1 f=7372800Гц band=9600,
   UBRRL=47;   //   нормальный асинхронный двунаправленный режим работы
   
//         RXC         -   завершение приёма
//         |TXC      -   завершение передачи
//         ||UDRE       -   отсутствие данных для отправки
//         |||FE      -   ошибка кадра
//         ||||DOR      -   ошибка переполнение буфера
//         |||||PE      -   ошибка чётности
//         ||||||U2X   -   Двойная скорость
//         |||||||MPCM   -   Многопроцессорный режим
//         76543210
   UCSRA=0b00000000;

//         RXCIE      -   прерывание при приёме данных
//         |TXCIE      -   прерывание при завершение передачи
//         ||UDRIE      -   прерывание отсутствие данных для отправки
//         |||RXEN      -   разрешение приёма
//         ||||TXEN   -   разрешение передачи
//         |||||UCSZ2   -   UCSZ0:2 размер кадра данных
//         ||||||RXB8   -   9 бит принятых данных
//         |||||||TXB8   -   9 бит переданных данных
//         76543210
   UCSRB=0b00011000;   //   разрешен приём и передача по UART

//         URSEL      -   всегда 1
//         |UMSEL      -   режим:1-синхронный 0-асинхронный
//         ||UPM1      -   UPM0:1 чётность
//         |||UPM0      -   UPM0:1 чётность
//         ||||USBS   -   топ биты: 0-1, 1-2
//         |||||UCSZ1   -   UCSZ0:2 размер кадра данных
//         ||||||UCSZ0   -   UCSZ0:2 размер кадра данных
//         |||||||UCPOL-   в синхронном режиме - тактирование
//         76543210
   UCSRC=0b10000110;   //   8-битовая посылка
}

//   UART
void send_Uart(unsigned char c)//   Отправка байта
{
   while(!(UCSRA&(1<<UDRE)))   //   Устанавливается, когда регистр свободен
   {}
   UDR = c;
}

void send_Uart_str(unsigned char *s)//   Отправка строки
{
   while (*s != 0) send_Uart(*s++);
}

void send_int_Uart(unsigned int c)//   Отправка числа от 0000 до 9999
{
   unsigned char temp;
   c=c%10000;
   temp=c/100;
   send_Uart(temp/10+'0');
   send_Uart(temp%10+'0');
   temp=c%100;
   send_Uart(temp/10+'0');
   send_Uart(temp%10+'0');
}

unsigned char getch_Uart(void)//   Получение байта
{
   while(!(UCSRA&(1<<RXC)))   //   Устанавливается, когда регистр свободен
   {}
   return UDR;
}




// Прерывание по переполнению T2
ISR(TIMER2_OVF_vect)
{   

t++;

}

int main(void)
{
   DDRC = 0b00000001;            //   инициализация порта C, PC0 - выход
   init_UART();               //   инициализация UART

     // Настройка Таймера 2
    TIMSK |= (1 << TOIE2); // Разрешение прерывания по таймеру2
    TCCR2 |= (1 << CS20);  // Без предделителя

   //разрешаем прерывания
   sei();

    while(1)                  //   бесконечный рабочий цикл
    {
      
                if(UCSRA&(1<<RXC))         //   если пришёл байт по UART
      {
       if(getch_Uart()=='1') PORTC = 0b00000001;         //   Включаем диод PC0 = 1 = Vcc
       if(getch_Uart()=='2') PORTC = 0b00000000;         //   Включаем диод PC0 = 1 = Vcc
      }


            
    }
}


Вот код, прием одного байта, даже не знаю как мне организовать буфер, чтобы сложить приходящие цифры до прихода запятой в строку.
Gin87
Открыл глаза
Сообщения: 74
Зарегистрирован: Вс янв 24, 2010 21:29:07

Re: UART ATmega8

Сообщение Gin87 »

Аlex писал(а):
Gin87 писал(а):Возможно у кого-то есть код
Вряд ли у кого-то будет такой специфический код.

Gin87 писал(а):не получается.
Пишу на С в AVR Studio 4.
Что не получается конкретно ? Показывайте.

Конец строки будет определять символ "," (запятая).
Вообще, конец строки определяется нулевым символом ('\0'). Почему у Вас запятая - :dont_know:


Не, идея в том, когда приходит символ запятая, значит все стоп, строка закончена, можно преобразовывать в число.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: UART ATmega8

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

даже не знаю как мне организовать буфер
https://www.google.ru/search?q=%D0%BC%D ... 0%A1%D0%B8

Ну а проверка символа - обычное условие.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: UART ATmega8

Сообщение ARV »

используйте возможности стандартной библиотеки Си - функцию scanf
я рассказывал, как это сделать, в своей статейке.

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

Мой уютный бложик... заходите!
Аватара пользователя
dr.doc
Это не хвост, это антенна
Сообщения: 1368
Зарегистрирован: Вс мар 28, 2010 12:52:22
Откуда: Беларусь

Re: UART ATmega8

Сообщение dr.doc »

Я подобную проблему решал для Modbus устройства. Правда там в качестве окончания сообщения (строки) используется время, необходимое для передачи 1,5 байт информации на принятой скорости. В каждом прерывании по приему байта я обнулял таймер. А в прерывании по таймеру запрещал прием и разрешал обработку данных.
Буфер реализуется просто - собственно сам буфер и счетчик числа принятых байт. При переполнении счетчика (слишком длинное сообщение) выставляется флаг аварии, который потом и обрабатывается наравне с принятой информацией.
«Еще я хотел бы, чтобы наши ученые изобрели какой-то новый источник энергии, чтобы мы на коленях не ползали даже перед нашими братьями, умоляя их и выпрашивая тонну нефти или кубометр газа», — рассказал белорусский президент.
Аватара пользователя
Mishany
Электрический кот
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Re: UART ATmega8

Сообщение Mishany »

Какова максимальная длина передаваемого числа?
Если решать задачу в лоб: подготовить массив необходимой длины, принимая байты проверять на наличие "," как словили запятую массив на обработку ...
передача в кодировке ascii?
если да то приходить будет 48-57 ("0-9")
код 44 "," - конец передачи

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


unsigned char temp[];
unsigned char i;  //длина принятого массива
unsigned long data, S;  //выбрать наиболее подходящий тип
ISR(USART_RX_vect)   //прерывание по приему
{
   temp[i]=UDR;
   if (temp[i]==44)
   {
//собираем число примерно так:
   data = 0;
   S = 1;
   for(i=i-1; i!=0; i--)
      {
      data = data+(temp[i]-48)*S;
      S = S*10;
      }
   }
   else
   {
   i++;
   }
}
Gin87
Открыл глаза
Сообщения: 74
Зарегистрирован: Вс янв 24, 2010 21:29:07

Re: UART ATmega8

Сообщение Gin87 »

Текущий код:

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

#ifndef F_CPU
#define F_CPU 7372800UL   //   рабочая частота
#endif

#include <avr/io.h>
#include <util/delay.h>      //   для _delay_ms()
#include <avr/interrupt.h>

volatile unsigned long t=0;
volatile unsigned int v=0;
//==========
volatile unsigned char temp[];
volatile unsigned char i=0;   //длина принятого массива
volatile unsigned long data, S;  //выбрать наиболее подходящий тип
//==========

int init_UART(void)
{
   //   Установка скорости 9600
   UBRRH=0;   //   UBRR=f/(16*band)-1 f=7372800Гц band=9600,
   UBRRL=47;   //   нормальный асинхронный двунаправленный режим работы
   
//         RXC         -   завершение приёма
//         |TXC      -   завершение передачи
//         ||UDRE       -   отсутствие данных для отправки
//         |||FE      -   ошибка кадра
//         ||||DOR      -   ошибка переполнение буфера
//         |||||PE      -   ошибка чётности
//         ||||||U2X   -   Двойная скорость
//         |||||||MPCM   -   Многопроцессорный режим
//         76543210
   UCSRA=0b00000000;

//         RXCIE      -   прерывание при приёме данных
//         |TXCIE      -   прерывание при завершение передачи
//         ||UDRIE      -   прерывание отсутствие данных для отправки
//         |||RXEN      -   разрешение приёма
//         ||||TXEN   -   разрешение передачи
//         |||||UCSZ2   -   UCSZ0:2 размер кадра данных
//         ||||||RXB8   -   9 бит принятых данных
//         |||||||TXB8   -   9 бит переданных данных
//         76543210
//   UCSRB=0b10011000;   //   разрешен приём и передача по UART
UCSRB|=(1<<RXEN)|(1<<RXCIE)|(1<<TXEN);

//         URSEL      -   всегда 1
//         |UMSEL      -   режим:1-синхронный 0-асинхронный
//         ||UPM1      -   UPM0:1 чётность
//         |||UPM0      -   UPM0:1 чётность
//         ||||USBS   -   топ биты: 0-1, 1-2
//         |||||UCSZ1   -   UCSZ0:2 размер кадра данных
//         ||||||UCSZ0   -   UCSZ0:2 размер кадра данных
//         |||||||UCPOL-   в синхронном режиме - тактирование
//         76543210
   UCSRC=0b10000110;   //   8-битовая посылка
}


//=========
ISR(USART_RXC_vect)   //прерывание по приему
{
   temp[i]=UDR;
   if (temp[i]==',')
   {
   PORTB = 0b00000001;
//собираем число примерно так:
   data = 0;
   S = 1;
   for(i=i-1; i!=0; i--)
      {
      //data = data+(temp[i]-48)*S;
      //S = S*10;
     data = data+temp[i];
      }
   }
   else
   {
   i++;
   }
}

//==========



int main(void)
{
   DDRB = 0b00000001;            //   инициализация порта C, PC0 - выход
   init_UART();               //   инициализация UART

   //разрешаем прерывания
   sei();

    while(1)                  //   бесконечный рабочий цикл
    {

   asm("nop");
   
    }
}

Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: UART ATmega8

Сообщение ARV »

Gin87 писал(а):Текущий код
и чо?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Mishany
Электрический кот
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Re: UART ATmega8

Сообщение Mishany »

говорит ресетится на приеме по уарт
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: UART ATmega8

Сообщение ARV »

Mishany писал(а):говорит
кому? и в любом случае - и чо? :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: UART ATmega8

Сообщение COKPOWEHEU »

volatile unsigned char temp[];
Где размер массива? Без этого нельзя обращаться к такому массиву без извращений, которые я бы вам не рекомендовал.
// Установка скорости 9600
UBRRH=0; // UBRR=f/(16*band)-1 f=7372800Гц band=9600,
UBRRL=47; // нормальный асинхронный двунаправленный режим работы
Удобнее воспользоваться макросом.

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

#define UART_BAUD 9600
#define UART_UBRR ((F_CPU / 8 / UART_BAUD + 1)/2) //даже с округлением до ближайшего целого. Впрочем, писал из головы, лучше проверьте перед использованием
UBRR = UART_UBRR;

UCSRB|=(1<<RXEN)|(1<<RXCIE)|(1<<TXEN);

// URSEL - всегда 1
// |UMSEL - режим:1-синхронный 0-асинхронный
// ||UPM1 - UPM0:1 чётность
// |||UPM0 - UPM0:1 чётность
// ||||USBS - топ биты: 0-1, 1-2
// |||||UCSZ1 - UCSZ0:2 размер кадра данных
// ||||||UCSZ0 - UCSZ0:2 размер кадра данных
// |||||||UCPOL- в синхронном режиме - тактирование
// 76543210
UCSRC=0b10000110; // 8-битовая посылка
Расписывать биты прямо в коде не стоит - кому надо посмотрят в даташите, а вот указать какие биты выставляете (как вы сделали с UCSRB, но почему-то не сделали с UCSRC) стоит.
ISR(USART_RXC_vect) //прерывание по приему

Возможно, лучше выставить флаг в какой-нибудь переменной, а обработку вести уже в основном цикле.
Аватара пользователя
Mishany
Электрический кот
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Re: UART ATmega8

Сообщение Mishany »

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

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

unsigned char temp[10];
unsigned char i;  //длина принятого массива
unsigned long data, S;  //выбрать наиболее подходящий тип
ISR(USART_RXС_vect)   //прерывание по приему
{
   temp[i]=UDR;
   if (temp[i]==44)
   {
//собираем число примерно так:
   data = 0;
   S = 1;
   for(i=i-1; i!=255; i--)   //255 чтобы не потерять нулевой элемент массива приема
      {
      data = data+(temp[i]-48)*S;
      S = S*10;
      }
i=0;
   }
   else
   {
   i++;
   }
}
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: UART ATmega8

Сообщение COKPOWEHEU »

Прием с преобразованием в число можно делать и на лету

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

volatile unsigned int uart_data=0;
volatile char uart_rx_flag = 0;
ISR(USART_RXС_vect){
  char udr = UDR; //именно в случае UART буферизация, возможно, и не нужна, но предпочитаю перестраховаться
  if( udr == ',' ){
    uart_rx_flag = 1; //выставляем флаг окончания приема числа, пусть теперь с ним основная программа разбирается
  }else{
    uart_data *= 10; //переходим к очередному разряду
    uart_data += (udr - '0'); //и записываем туда считанную цифру
  }
}
Вопрос, какая запись кодов символов лучше, спорный. Мне кажется более наглядной запись самого символа.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: UART ATmega8

Сообщение ARV »

COKPOWEHEU писал(а):Удобнее воспользоваться макросом.
особенно тем, которые разработчики тулчейна сделали "стандартным".
я имею ввиду это

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

#include <util/setbaud.h>
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: UART ATmega8

Сообщение da-nie »

Если число в текстовом виде, то преобразовать можно с помощью atoi или atof. (long a=atoi("123")).
Только не забудьте вместо ',' в конце строки вставить 0.

Если же вы не уверены, что там точно придёт число, то вас спасёт конечный автомат, которому придётся описать правила перехода в зависимости от символа для числа. :) Но это уже отдельная тема.
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: UART ATmega8

Сообщение COKPOWEHEU »

особенно тем, которые разработчики тулчейна сделали "стандартным".
Хорошо бы, но они чего-то там перемудрили, либо это я чего-то не понимаю. Например, зачем нужен режим не-удвоенной скорости UART (U2X=0)? Даже при максимальной тактовой частоте 20 МГц "ускоренный" режим дает минимальную скорость обмена 610 байт/сек.
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: UART ATmega8

Сообщение Z_h_e »

ДШ нет перед глазами. При выключенной двойной скорости, количество внутренних стробов на бит во сколько то раз больше. Из-за этого при приеме три выборки на бит более в середине. А при передаче временные границы бита ближе к расчетным. Это сколько то уменьшает требования к точности тактовой частоты. Вроде как-то так.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: UART ATmega8

Сообщение COKPOWEHEU »

Похоже, что отлов начала передачи (активный фронт стартового бита) идет как середина между тактами - такт - середина между следующими тактами, независимо от режима. Тогда точность синхронизации будет 1 такт в любом случае, но в режиме одинарной скорости 1 такт соответствует половине бита, то есть в таком режиме время старта определяется вдвое точнее.
А вот прием значащих битов в случае двойной скорости - одна выборка, а в случае одинарной - выборка и два соседних промежутка между тактами. То есть для одинарной скорости 1 бит принимается за 2 такта и усредняется по "точному времени", предыдущему такту и следующему, то есть 4-му биту соответствуют 3.5 - 4 - 4.5 выборки. А при двойной скорости берется только одно "центральное" значение. Тогда одинарная скорость будет более помехозащищенной. С другой стороны, комбинация вроде 010 (x-0.5 ... x ... x+0.5 отсчеты) может быть распознана как 0, а не как 1. Впрочем, разработчики должны были это предусмотреть.
В результате появляется выбор: большая точность частоты или большая помехозащищенность.
Я правильно понял этот кусок из даташита?
Ответить

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