Страница 1 из 2
UART ATmega8
Добавлено: Чт июл 28, 2016 20:14:59
Gin87
Всем привет! Возможно у кого-то есть код. Помогите пожалуйста.
Суть вот в чем. Нужно передавать числа из терминала в МК. Например 5000 или 125000. Понятно, что терминал будет передавать по одной цифре, побайтно. Конец строки будет определять символ "," (запятая).
Принимать один байт получается. А вот принять побайтно в буфер, получить строку, где запятая конец строки, а потом преобразовать в число не получается.
Пишу на С в AVR Studio 4.
Кто чем может
P.S. Да в инете есть примеры, но часто куски вырванные и в общую картину сложить не получается. Переменные пропущены. К тому избыточность тоже не нужна, всякие там кольцевые буферы и прочее.
Re: UART ATmega8
Добавлено: Чт июл 28, 2016 20:23:43
Аlex
Gin87 писал(а):Возможно у кого-то есть код
Вряд ли у кого-то будет такой специфический код.
Gin87 писал(а):не получается.
Пишу на С в AVR Studio 4.
Что не получается конкретно ? Показывайте.
Конец строки будет определять символ "," (запятая).
Вообще, конец строки определяется нулевым символом ('\0'). Почему у Вас запятая -

Re: UART ATmega8
Добавлено: Чт июл 28, 2016 20:37:31
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
}
}
}
Вот код, прием одного байта, даже не знаю как мне организовать буфер, чтобы сложить приходящие цифры до прихода запятой в строку.
Re: UART ATmega8
Добавлено: Чт июл 28, 2016 20:38:54
Gin87
Аlex писал(а):Gin87 писал(а):Возможно у кого-то есть код
Вряд ли у кого-то будет такой специфический код.
Gin87 писал(а):не получается.
Пишу на С в AVR Studio 4.
Что не получается конкретно ? Показывайте.
Конец строки будет определять символ "," (запятая).
Вообще, конец строки определяется нулевым символом ('\0'). Почему у Вас запятая -

Не, идея в том, когда приходит символ запятая, значит все стоп, строка закончена, можно преобразовывать в число.
Re: UART ATmega8
Добавлено: Чт июл 28, 2016 20:44:09
Аlex
даже не знаю как мне организовать буфер
https://www.google.ru/search?q=%D0%BC%D ... 0%A1%D0%B8
Ну а проверка символа - обычное условие.
Re: UART ATmega8
Добавлено: Чт июл 28, 2016 20:51:35
ARV
используйте возможности стандартной библиотеки Си - функцию
scanf
я рассказывал, как это сделать, в
своей статейке.
внимание: мой пример не использует прерывания!
Re: UART ATmega8
Добавлено: Чт июл 28, 2016 22:19:06
dr.doc
Я подобную проблему решал для Modbus устройства. Правда там в качестве окончания сообщения (строки) используется время, необходимое для передачи 1,5 байт информации на принятой скорости. В каждом прерывании по приему байта я обнулял таймер. А в прерывании по таймеру запрещал прием и разрешал обработку данных.
Буфер реализуется просто - собственно сам буфер и счетчик числа принятых байт. При переполнении счетчика (слишком длинное сообщение) выставляется флаг аварии, который потом и обрабатывается наравне с принятой информацией.
Re: UART ATmega8
Добавлено: Чт июл 28, 2016 22:45:10
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++;
}
}
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 14:21:33
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");
}
}
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 14:46:40
ARV
Gin87 писал(а):Текущий код
и чо?
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 14:48:00
Mishany
говорит ресетится на приеме по уарт
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 14:50:58
ARV
Mishany писал(а):говорит
кому? и в любом случае - и чо?

Re: UART ATmega8
Добавлено: Пт июл 29, 2016 17:05:14
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) //прерывание по приему
Возможно, лучше выставить флаг в какой-нибудь переменной, а обработку вести уже в основном цикле.
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 18:18:06
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++;
}
}
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 19:10:47
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'); //и записываем туда считанную цифру
}
}
Вопрос, какая запись кодов символов лучше, спорный. Мне кажется более наглядной запись самого символа.
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 19:19:04
ARV
COKPOWEHEU писал(а):Удобнее воспользоваться макросом.
особенно тем, которые разработчики тулчейна сделали "стандартным".
я имею ввиду это
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 19:44:20
da-nie
Если число в текстовом виде, то преобразовать можно с помощью atoi или atof. (long a=atoi("123")).
Только не забудьте вместо ',' в конце строки вставить 0.
Если же вы не уверены, что там точно придёт число, то вас спасёт конечный автомат, которому придётся описать правила перехода в зависимости от символа для числа.

Но это уже отдельная тема.
Re: UART ATmega8
Добавлено: Пт июл 29, 2016 20:19:24
COKPOWEHEU
особенно тем, которые разработчики тулчейна сделали "стандартным".
Хорошо бы, но они чего-то там перемудрили, либо это я чего-то не понимаю. Например, зачем нужен режим не-удвоенной скорости UART (U2X=0)? Даже при максимальной тактовой частоте 20 МГц "ускоренный" режим дает минимальную скорость обмена 610 байт/сек.
Re: UART ATmega8
Добавлено: Сб июл 30, 2016 09:46:04
Z_h_e
ДШ нет перед глазами. При выключенной двойной скорости, количество внутренних стробов на бит во сколько то раз больше. Из-за этого при приеме три выборки на бит более в середине. А при передаче временные границы бита ближе к расчетным. Это сколько то уменьшает требования к точности тактовой частоты. Вроде как-то так.
Re: UART ATmega8
Добавлено: Сб июл 30, 2016 10:56:22
COKPOWEHEU
Похоже, что отлов начала передачи (активный фронт стартового бита) идет как середина между тактами - такт - середина между следующими тактами, независимо от режима. Тогда точность синхронизации будет 1 такт в любом случае, но в режиме одинарной скорости 1 такт соответствует половине бита, то есть в таком режиме время старта определяется вдвое точнее.
А вот прием значащих битов в случае двойной скорости - одна выборка, а в случае одинарной - выборка и два соседних промежутка между тактами. То есть для одинарной скорости 1 бит принимается за 2 такта и усредняется по "точному времени", предыдущему такту и следующему, то есть 4-му биту соответствуют 3.5 - 4 - 4.5 выборки. А при двойной скорости берется только одно "центральное" значение. Тогда одинарная скорость будет более помехозащищенной. С другой стороны, комбинация вроде 010 (x-0.5 ... x ... x+0.5 отсчеты) может быть распознана как 0, а не как 1. Впрочем, разработчики должны были это предусмотреть.
В результате появляется выбор: большая точность частоты или большая помехозащищенность.
Я правильно понял этот кусок из даташита?