UART ATmega8

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

Сообщение Gin87 »

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

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

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

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

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

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

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

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

Сообщение 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
		}


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

Сообщение Gin87 »

Аlex писал(а):
Gin87 писал(а):Возможно у кого-то есть код
Вряд ли у кого-то будет такой специфический код.
Gin87 писал(а):не получается.
Пишу на С в AVR Studio 4.
Что не получается конкретно ? Показывайте.
Конец строки будет определять символ "," (запятая).
Вообще, конец строки определяется нулевым символом ('\0'). Почему у Вас запятая - :dont_know:
Не, идея в том, когда приходит символ запятая, значит все стоп, строка закончена, можно преобразовывать в число.
Реклама
Эиком - электронные компоненты и радиодетали
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

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

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

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

Сообщение ARV »

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

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

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

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

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

Сообщение 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++;
	}
}
Открыл глаза
Сообщения: 74
Зарегистрирован: Вс янв 24, 2010 21:29:07

Сообщение 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
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18707
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

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

Сообщение Mishany »

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

Сообщение ARV »

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

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

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

Сообщение 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++;
   }
}
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение 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
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18707
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

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

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

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

Сообщение 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
Контактная информация:
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

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

Сообщение Z_h_e »

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

Сообщение COKPOWEHEU »

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

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