Всем привет).
Может, кому-то эта статья сэкономит много времени и нервов.
Недавно по работе встретился с интересной задачкой.
Нужно было передать на железку по порту RS485 информацию для проверки работоспособности последней.
Так как не всегда имеется в ремонте вся система, то для начала нужно было посмотреть, на заведомо исправной системе, что же там между ними (железками) передаётся.
Логический анализатор показал что девайсы общаются по не совсем стандартному, а по 9ти битному протоколу (USART 9n1).
А это усложняло задачу, так-так известные мне терминальные программы его не поддерживают. И без бубна не обойтись))).
Начались поиски решения.
Через некоторое время стало понятно, что AVR позволяет это делать и даже в даташите подробно это описывает.
Дело за малым. Реализация задуманного))).
Все регистры выставлены по документу………..Для Atmega8a.
void USART_Init( unsigned int speed) //Инициализация модуля USART
{
UBRRH = (unsigned char)(speed>>8);
UBRRL = (unsigned char)speed;
UCSRB=(1<<RXEN)|( 1<<TXEN); //Включаем прием и передачу по USART
UCSRB |= (1<<RXCIE); //Разрешаем прерывание при передаче
UCSRA |= (1<<U2X); //удвоение скорости
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
UCSRB |= (1<<UCSZ2); // Включаем 9bit режим
// Обращаемся именно к регистру UCSRC (URSEL=1)
// ассинхронный режим (UMSEL=0), без контроля четности (UPM1=0 и UPM0=0)
// 1 стоп-бит (USBS=0), 8-бит посылка (UCSZ1=1 и UCSZ0=1)
// если (UCSZ1=1 и UCSZ0=1 и UCSZ2=1) 9bit mode.
// UCSRC |= (1<<UPM1);//четность
}
По даташиту передача 9го бита происходит установкой или сбросом TXB8.
То есть, установили бит, передаётся 1 в старшем 9ом разряде, сбросили – 0.
void USART_Transmit( unsigned int data ) // функция передачи 9ти бит из даташита.
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) )
;
/* Copy ninth bit to TXB8 */
UCSRB &= ~(1<<TXB8);
if ( data & 0x0100 ) //не понял, что они хотели этим сделать.
UCSRB |= (1<<TXB8);
/* Put data into buffer, sends the data */
UDR = data;
}
И вот незадача, числа размером до 1 байт передаются без проблем, а числа больше 0xFF (255) нет).
А устройство передаёт числа до 510.
Предлагаю решение. Может и не самое лучшее, но вполне работоспособное.
int main(void)
{
USART_Init (103);//9600
//------------------------------------------------------------------------------------
while(1)
{
for (i=0; i<22; i++)
{
code_simbol = simbol[i]; //символ из массива
//-------------------------------------отправка в UART--------------------------------
if (code_simbol > 255)
{
pr=1; // флаг передачи символа больше 0xff (255 десятичное)
}
else
{
pr=0; // флаг передачи символа меньше 0xff
}
USART_Transmit(code_simbol,pr);//собственно сама функция отаравки
}
}
}
А теперь и сама функция передачи .
void USART_Transmit( unsigned char data, uint8_t prisnak ) //Функция отправки по USART
{
while ( !(UCSRA & (1<<UDRE)) ); //Ожидание опустошения буфера приема
if (prisnak==1)
{
UCSRB |= (1<<TXB8); //устанавливаем для передачи еденицы в старшем разряде
}
else
{
UCSRB &= ~(1<<TXB8); //сбрасываем старший разряд
}
/* Put data into buffer, sends the data */
UDR = data; //Начало передачи данных
asm volatile ("nop");
Соответственно если число для предачи мньше 256 мы передаём его при нулевом 9ом бите.
Ну а если больше то 9й бит выставляем в единицу.
А вот и результат.