Пн июн 07, 2021 23:36:12
/* ------ асинхронный (9-N-1) ------ РАБОТАЕТ --- но есть нюанс ошибки кадрирования (FE0)-------
* GccApplication57.c
* ----- прога для равноправных МК ---------- индикация битов ошибок (FE0, DOR0, UPE0) модуля USART0 --------
* Created: 02.06.2021 15:45:07
* Author : Admin
*/
// задача-организовать поочередную отправку и прием 9-ти битной посылки циклически (полудуплекс) и опросить все биты ошибок (FE0, DOR0, UPE0) модуля USART0,
// затем значение каждого бита из 3 вывести на свой пин индикации и конечно же на индикацию вывести 9 бит посылки
//
// в программе мы изучаем 9-и битный режим передачи и хотим наблюдать на светодиодах есть ли ошибки модуля USART0 и также саму посылку хотим видеть на светодиодах,
// для этого под ошибки модуля USART0 назначим такие светодиоды
// (PORTD7) ---- значение (FE0) ----- Флаг ошибки кадрирования
// (PORTD6) ---- значение (DOR0) ----- Флаг переполнения
// (PORTD5) ---- значение (UPE0) ----- Флаг ошибки контроля четности
// (PORTD3) ---------- значение 9-го бита принятой посылки
// (PORTB ) ---------- 8 младших битов принятой посылки
//
// прога работает так, в суперцикле по прерыванию системного таймера отправляем байты бегущего огонька другому мк не читая принятые взамен байты,
// затем по прерыванию завершение приема мы получаем 9-ти битную посылку и выводим все полученые биты на светодиодную индикацию (9 битов посылка и 3 бита ошибок)
// получается у нас 9-и битный бегущий огонек и почему то в момент получения установленого 9-го бита у нас зажигается ошибка кадрирования бит (FE0), затем
// когда в следующей посылке 9-ый бит сброшен сбрасывается и ошибка
//
//
//
// частота ядра 1 МГц , скорость = 2400 бит/с при UBRR = 25 и U2X0 = 0 таблица даташит, но мы по формуле в дефайнах вычислим (UBRR)
// асинхронный USART0 ---------- (UMSEL10=0, UMSEL00=0)
// отключена проверка на четность и нечетность ----- (UPM01=0, UPM00=0)
// 1 стоп, 9 data, без проверки четности, асинхронный (9-N-1)
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL // тактовая частота МК
#define BAUD 2400 // BAUD — скорость передачи, бит/с;
#define MYUBRR F_CPU/16/BAUD-1 // РАСЧЕТ (UBRR) ПО ИЗВЕСТНОЙ СКОРОСТИ ------
//---------- ПОРТ ИНДИКАЦИИ ----------
#define PORT_LED PORTB
#define DDR_LED DDRB
volatile uint8_t sis_taimer =0; // переменная системного таймера
//----------
void TIMER0_init(void) // инициализация модуля таймера Т0 режим СТС прерывание и сброс по совпадению с содержимым регистра (OCR0A)
{
TIMSK0 = 0b00000010; // бит РВ1(OCIE0A) устанавливаем в 1, разрешения прерывания по совпадению блока А таймера /счетчика Т0
TCCR0A = 0b00000010; // биты (WGM02,WGM00) сбрасываем в 0, (WGM01) установим в 1 настройка ------- режима СТС
TCCR0B = 0b00000010; // настраиваем предделитель на 8 (биты CS02=0,CS01=1,CS00=0),бит В3(WGM02) сбрасываем в 0
OCR0A = 100; // запишем 100 в регистр сравнения (OCR0A) блока А
GTCCR = 0b00000001; // бит РВ0(PSRSYNC) устанавливаем в 1, Сброс предделителя TO (сбрасываем пред. в конце настроек)
}
//----------
void USART0_Init_9_N_1( unsigned int ubrr) // инициализация приемопередатчика USART0.
{
UBRR0H = (uint8_t)(ubrr>>8); // сместив двух байтовый (ubrr) 8 раз вправо мы впишем в одно байтовый регистр (UBRR0H) старший байт
UBRR0L = (uint8_t)ubrr; // запишем рассчитанное в дефайнах число в младший одно байтовый регистр скорости (UBRR0L)
UCSR0B = (1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0)|(1<<UCSZ02); // разрешаем работу модуля передатчика и приемника, разрешение прерывания по завершении приема
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); // 1 стоп-бит, размер слова 9 бит (9-N-1)
}
//----------
void USART_Transmit( uint16_t data ) // передаем 9 битный символ так - помещаем 9-тый бит в (TXB80), а затем записываем младшие 8 битов в (UDR0)
{
while ( !( UCSR0A & (1<<UDRE0)) ); // ожидаем опустошение приемного регистра
if ( data & 0x0100 ) // проверяем 9 по счету бит переменной (data), если этот бит = 1, то выполняется выражение в скобках
{
UCSR0B |= (1<<TXB80); // устанавливаем 9 по счету бит передачи (TXB80) в 1
}
else // иначе 9 по счету бит переменной (data) не равен 1, то есть = 0, то выполняется выражение в скобках
{
UCSR0B &= ~(1<<TXB80); // сбрасываем 9 по счету бит передачи (TXB80) в 0
}
UDR0 = data; // отправляем оставшиеся 8 бит в регистр данных
}
//----------
uint16_t USART_Receive( void ) // прием 9-ти битной посылки в режиме (9-N-1). выдаем из функции через ретурн 2-х байтное слово
{ // 8-0-ой разряд ---------- младший байт посылки
// 9-ой разряд --- бит (RXB80) -- 9 бит посылки
// 10-ый разряд --- бит (UPE0) -- Флаг ошибки контроля четности
// 11-ой разряд --- бит (DOR0) -- Флаг переполнения
// 12-ий разряд --- бит (FE0) -- Флаг ошибки кадрирования
while ( !(UCSR0A & (1<<RXC0)) ); // ожидаем завершения приема ( ПРИМЕНЯЕМ ЭТУ СТРОКУ, ЕСЛИ ФУНКЦИЯ РАБОТАЕТ НЕ В ПРЕРЫВАНИИ ПО ЗАВЕРШЕНИЮ ПРИЕМА)
uint8_t status, resh, resl, err_stat; // объявим переменные
status = UCSR0A; // считываем значение регистра статуса (UCSR0A) в переменную (status), ( тут у нас флаги FE0, DOR0, UPE0)
resh = UCSR0B; // считываем значение регистра управления (UCSR0B) в переменную (resh), в нем же 9 бит (RXB80)
resl = UDR0; // считываем полученый 8 битный байт данных из регистра данных (UDR0)
status = (status >> 1) & 0x0E; // сместим байт (status) на одну позицию вправо, тем самым бит (UPE0) со 2-го разряда перейдет в 1-ой, бит (DOR0) с 3-го
// во 2-ый, бит (FE0) с 4-го в 3-ой, затем на байт набросим маску 0x0E и все разряды обнулятся кроме 1,2,3 в которых
// теперь наши статусные биты (FE0, DOR0, UPE0)
if (resh & 0x02) // проверяем 1 разряд переменной (resh) он же (RXB80) , если этот бит = 1, то выполняется выражение в скобках
{
status |= (1<<0); // установить в 1 нулевой разряд переменной (status), остальные биты не трогаем
}
else // иначе если 1 бит переменной (resh) равен 0 , то выполняется выражение в скобках
{
status &= ~(1<<0); // сбросить в 0 нулевой разряд переменной (status), остальные биты не трогаем
}
// теперь в переменной (status) у нас биты: 0-ой разряд --- бит (RXB80)
// 1-ый разряд --- бит (UPE0)
// 2-ой разряд --- бит (DOR0)
// 3-ий разряд --- бит (FE0)
return ((status << 8) | resl); // сместим байт (status) в старший байт двухбайтового слова и получится такая картина--
// 9-ой разряд --- бит (RXB80) -- 9 бит посылки
// 10-ый разряд --- бит (UPE0) -- Флаг ошибки контроля четности
// 11-ой разряд --- бит (DOR0) -- Флаг переполнения
// 12-ий разряд --- бит (FE0) -- Флаг ошибки кадрирования
// а в восемь остальных младших бит поместим значение из (UDR0)
}
//----------
uint16_t running_light(void) // ф-ия передает в вызывающюю ф-ию бегущий огонек (при каждом вызове в переданом 9-и битном слове еденица смещается на разряд влево)
{ // примерно так- сначала 0b000000001, при следующем вызове 0b000000010, потом 0b000000100 и так по 0b100000000 и все заново
uint16_t data = 0; // создаем и задаем значение переменной (data),
static uint8_t a = 0; // создаем и задаем значение статической переменной (a), она у нас будет номером бита в нашем байте данных (data)
if (a>8) a=0; // защита от переполнения, как только (а) станет = 9 она обнулится , что бы не вылезти за размер 9 битного символа
data = (1 << a); // установка еденицы в бит (а) байта (data) с затиранием остальных битов, например было (0b000000001) потом стало (0b000000010)
a++ ; // инкрементируем наш номер бита в 9-ти битном слове)))
return (data); // передаем в вызывающюю функцию наш байт
}
//----------
ISR(USART_RX_vect) // прерывание по завершению приема
{
uint16_t in_data = 0 ; // в это двухбайтовое слово будем получать данные от другого МК
in_data = USART_Receive(); // получим в (in_data) нашу 9 битную посылку и статус ошибок модуля USART0
uint8_t x_low = in_data & 0xff; // обнуляем старший байт двухбайтового слова и остается значение младшего байта, которое запишем в (x_low)
uint8_t x_high = (in_data >> 8); // сдвигаем старший байт в младший байт двухбайтового слова и записываем в (x_high)
if (x_high & 0x01) // проверяем 0-ой разряд переменной x_high (там у нас значение 9 бита), если этот разряд = 1, то выполним выражение в скобках
{
PORTD |= (1<<PORTD3); // зажгем светодиод на пине (PORTD3)
}
else // иначе если нулевой разряд = 0 , то выполним выражение в скобках
{
PORTD &= ~(1<<PORTD3); // погасим светодиод на пине (PORTD3)
}
if (x_high & 0x02) // проверяем 1-ой разряд переменной x_high (там у нас значение (UPE0)), если этот разряд = 1, то выполним выражение в скобках
{
PORTD |= (1<<PORTD5); // зажгем светодиод на пине (PORTD5)
}
else // иначе если 1-ый разряд = 0 , то выполним выражение в скобках
{
PORTD &= ~(1<<PORTD5); // погасим светодиод на пине (PORTD5)
}
if (x_high & 0x04) // проверяем 2-ой разряд переменной x_high (там у нас значение (DOR0)), если этот разряд = 1, то выполним выражение в скобках
{
PORTD |= (1<<PORTD6); // зажгем светодиод на пине (PORTD6)
}
else // иначе если 2-ой разряд = 0 , то выполним выражение в скобках
{
PORTD &= ~(1<<PORTD6); // погасим светодиод на пине (PORTD6)
}
if (x_high & 0x01) // проверяем 3-ий разряд переменной x_high (там у нас значение (FE0)), если этот разряд = 1, то выполним выражение в скобках
{
PORTD |= (1<<PORTD7); // зажгем светодиод на пине (PORTD7)
}
else // иначе если 3-ий разряд = 0 , то выполним выражение в скобках
{
PORTD &= ~(1<<PORTD7); // погасим светодиод на пине (PORTD7)
}
PORT_LED = x_low; // принятый младший байт выведем в порт индикации
}
//----------
ISR(TIMER0_COMPA_vect) // прерывание по совпадению блока А таймера Т0
{
sis_taimer ++; // инкрементируем системный таймер
}
//----------
int main(void)
{
DDRD |= (1<<DDD7)|(1<<DDD6)|(1<<DDD5)|(1<<DDD3); // конфигурируем пины DDD7,DDD6,DDD5 и DDD3 на выход, на них будут 9 бит посылки и три бита ошибок ВАРТа
DDR_LED = 0b11111111; // на выход ( на нем наши индикаторные светоды)
TIMER0_init (); // инициализация и настройка модуля таймера Т0
USART0_Init_9_N_1(MYUBRR); // передаем рассчитанное значение скорости (MYUBRR) в блок инициализации USART0
uint16_t out_data = 0 ; // двухбайтовый символ для отправки другому мк по USART0
sei();
while (1)
{
if (sis_taimer == 100) // системный таймер
{
out_data = running_light(); // бегущий огонек загоняем в переменную на отправку другому МК
USART_Transmit (out_data); // отправляем байт другому мк
sis_taimer =0; // сбросим таймер и ждем следующего тика системного таймера
}
}
}
Вт июн 08, 2021 13:09:22
Ср июн 09, 2021 11:08:08
Ср июн 09, 2021 22:24:37
unsigned int USART_Receive( void ) // Получим статус и 9-й бит, затем данные из буфера приемника
{
unsigned char status, resh, resl; // объявим переменные
while ( !(UCSR0A & (1<<RXC0)) ); // ожидаем завершения приема (получение данных)
status = UCSR0A; // считываем значение регистра статуса (UCSR0A) в переменную (status), ( тут у нас флаги FE0, DOR0, UPE0)
resh = UCSR0B; // считываем значение регистра управления (UCSR0B) в переменную (resh), в нем же 9 по счету бит (RXB80)
resl = UDR0; // считываем полученный 8 битный байт данных из регистра данных (UDR0)
if ( status & (1<<FE0)|(1<<DOR0)|(1<<UPE0) ) // проверяем установлены ли биты (FE0, DOR0, UPE0), если хоть один бит установлен, то выполняем код в скобках
{
return -1; // ошибка приемопередачи модуля USART0
}
resh = (resh >> 1) & 0x01; // сместим байт (resh) на одну позицию вправо, тем самым бит принимаемых данных (RXB80) с 1 позиции в байте перейдет на 0 позицию,
// затем затем на этот байт набросим маску 0x01 и все разряды обнулятся кроме нулевого разряда, в нем будет значение бита (RXB80)
return ((resh << 8) | resl); // сместим бит (RXB80) в 9 по счету бит, а в восемь остальных младших бит поместим значение из (UDR0)
}
uint16_t USART_Receive( void ) // прием 9-ти битной посылки в режиме (9-N-1). выдаем из функции через ретурн 2-х байтное слово
{ // 8-0-ой разряд ---------- младший байт посылки
// 9-ой разряд --- бит (RXB80) -- 9 бит посылки
// 10-ый разряд --- бит (UPE0) -- Флаг ошибки контроля четности
// 11-ой разряд --- бит (DOR0) -- Флаг переполнения
// 12-ий разряд --- бит (FE0) -- Флаг ошибки кадрирования
while ( !(UCSR0A & (1<<RXC0)) ); // ожидаем завершения приема ( ПРИМЕНЯЕМ ЭТУ СТРОКУ, ЕСЛИ ФУНКЦИЯ РАБОТАЕТ НЕ В ПРЕРЫВАНИИ ПО ЗАВЕРШЕНИЮ ПРИЕМА)
uint8_t status, resh, resl, err_stat; // объявим переменные
status = UCSR0A; // считываем значение регистра статуса (UCSR0A) в переменную (status), ( тут у нас флаги FE0, DOR0, UPE0)
resh = UCSR0B; // считываем значение регистра управления (UCSR0B) в переменную (resh), в нем же 9 бит (RXB80)
resl = UDR0; // считываем полученый 8 битный байт данных из регистра данных (UDR0)
status = (status >> 1) & 0x0E; // сместим байт (status) на одну позицию вправо, тем самым бит (UPE0) со 2-го разряда перейдет в 1-ой, бит (DOR0) с 3-го
// во 2-ый, бит (FE0) с 4-го в 3-ой, затем на байт набросим маску 0x0E и все разряды обнулятся кроме 1,2,3 в которых
// теперь наши статусные биты (FE0, DOR0, UPE0)
if (resh & 0x02) // проверяем 1 разряд переменной (resh) он же (RXB80) , если этот бит = 1, то выполняется выражение в скобках
{
status |= (1<<0); // установить в 1 нулевой разряд переменной (status), остальные биты не трогаем
}
else // иначе если 1 бит переменной (resh) равен 0 , то выполняется выражение в скобках
{
status &= ~(1<<0); // сбросить в 0 нулевой разряд переменной (status), остальные биты не трогаем
}
// теперь в переменной (status) у нас биты: 0-ой разряд --- бит (RXB80)
// 1-ый разряд --- бит (UPE0)
// 2-ой разряд --- бит (DOR0)
// 3-ий разряд --- бит (FE0)
return ((status << 8) | resl); // сместим байт (status) в старший байт двухбайтового слова и получится такая картина--
// 9-ой разряд --- бит (RXB80) -- 9 бит посылки
// 10-ый разряд --- бит (UPE0) -- Флаг ошибки контроля четности
// 11-ой разряд --- бит (DOR0) -- Флаг переполнения
// 12-ий разряд --- бит (FE0) -- Флаг ошибки кадрирования
// а в восемь остальных младших бит поместим значение из (UDR0)
Пн июн 14, 2021 22:59:02
Вт июн 15, 2021 23:16:17