Цифрова послідовність. Передавач (AVR)

На цьому уроці ми з Вами розберемо програмну реалізацію інтерфейсу передавача з цифрової, байт орієнтованої послідовності на мікроконтролері AVR.

Що означає, біт або байт орієнтована?? У випадку біт орієнтованої послідовності ми передаємо послідовність біт, які не об'єднуються в байти або слова (кілька байт), а передають незалежну, обособлену інформацію. Якщо нам необхідно передати набір чисел, наприклад, то на допомогу приходить байт орієнтована послідовність, біти якої об'єднуються в байти, слова і т.п.

Визначимося з протоколом. Як і годиться, спочатку передаємо стартові байти (замість стартової паузи). Потім дані: потужність двигуна - один байт, напрямок руху - один біт, напрямки повороту - два біти. Дані захистимо бітом парності - один біт. Додамо контрольну суму - один байт. У кінці кадру передамо стопові байти.

Розгляд програми почнемо з заголовочного файлу передавача transmitter.h.

Налаштуємо передавач. Вкажемо стартову та стопову послідовності...

#define START_SEQUENCE "ABC" //Стартові байти
#define STOP_SEQUENCE "&&"   //Стопові байти

Задамо швидкість передачі даних...

#define PULSE_DURATION() _delay_ms(1); //Частота передачі 1000 бод

Оголосимо перераховуваний тип даних...

enum logic_state {HIGH, LOW}; //Логічний стан

Оголосимо необхідні змінні...

unsigned char powerEngine,   //Потужність двигуна
         commandBuffer,      //Буфер команд
         charBuffer,         //Буфер передавача рядка   
         checkSum;           //Байт контрольної суми

enum {EVEN, ODD} parityBit = ODD; //Прапор парності

Для передачі даних знадобляться три функції: передача біта, байта і рядка, оголосимо їх...

void transmitBit(enum logic_state txBuffer); //Передача біта...
void transmitByte(unsigned char txBuffer); //Передача байта...
void transmitString(unsigned char txBuffer[]); //Передача рядка...

Налаштування портів вводу-виводу та АЦП з файлу initHard.c залишаються незмінними.

Тепер розглянемо основну програму.

Ми не використовуємо, процедуру ініціалізації прибираємо. Порти та АЦП проініціалізуємо...

initPORTs();    //Ініціалізація портів
initADC();      //Налаштування АЦП

Програма працює наступним чином: опитуємо клавіші повороту та заднього ходу...

//Опрос клавіші напрямку руху. Завантажити отримані дані в commandBuffer
if (!(PIND & (1 << PD0))) commandBuffer |= (1 << 0); else commandBuffer &= ~(1 << 0);

//Опрос клавіш напрямку повороту. Завантажити отримані дані в commandBuffer
if (!(PIND & (1 << PD1))) commandBuffer |= (1 << 1); else commandBuffer &= ~(1 << 1); //Вліво
if (!(PIND & (1 << PD2))) commandBuffer |= (1 << 2); else commandBuffer &= ~(1 << 2); //Вправо

Формуємо байти даних, для того щоб зберегти миттєве значення потужності в буфер...

//Завантажуємо миттєве значення потужності
     powerEngine = ADCH; //...або зупинити АЦП

Вичислюємо біт парності...

//Перевіряємо на чітність передавані дані
if ((powerEngine & (1 << 0)) || (commandBuffer & (1 << 0))) parityBit = ODD; else parityBit = EVEN;

Вичислюємо контрольну суму...

//Вичислюємо контрольну суму
checkSum = 0x41 + 0x42 + 0x43 + powerEngine + commandBuffer + 0x26 + 0x26;

Передаємо стартові байти...

//Передача стартових байт
     transmitString(START_SEQUENCE);

Передаємо дані...

//Передача байта потужності
     transmitByte(powerEngine);

//Передача байта commandBuffer
     transmitByte(commandBuffer);

Передаємо біт чітності...

//Передача біта чітності
     if (parityBit == EVEN) transmitBit(HIGH); else transmitBit(LOW);

Передаємо байт контрольної суми...

//Передача байта контрольної суми
     transmitByte(checkSum);

Передаємо стопові байти...

//Передача стопових байт
     transmitString(STOP_SEQUENCE);

АЦП опитує ручку газу (виконує вимірювання) в автоматичному режимі.

Розберемося з роботою функцій передачі данихФункція transmitBit. Якщо при виклику аргумент функції дорівнює HIGH, то конструкція...

if (txBuffer == HIGH) PORTB |= (1 << PB0); //Формуємо фронт

...формує фронт логічної одиниці. Далі слідує пауза PULSE_DURATION()...

_delay_ms(1); //Частота передачі 1000 бод

...яка забезпечує швидкість передачі в 1000 бод. За нею формуються безумовний срез...

PORTB &= ~(1 << PB0);  //Формуємо срез

У випадку, якщо аргумент функції дорівнює LOW, функція формує паузу в 1ms.

Функція transmitByte, в якості аргументу отримує один байт, 8 біт якого передаються в циклі...

for (unsigned char i = 0; i < 8; i++) {...

Перевіряємо «нульовий» біт, в залежності від його значення формуємо фронт або срез...

//Формуємо фронт/срез        
     if (txBuffer & (1 << 0)) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0);

...формуємо паузу...

PULSE_DURATION(); //Тривалість логічного стану

Зсув змінної txBuffer вправо на один розряд. Ця процедура повторюється 8 разів, для передачі 8 біт.

Функція transmitString, в якості аргументу отримує рядок символів. Перед початком передачі вичислюється кількість символів у рядку strlen(txBuffer), потім в циклі...

for (unsigned char i = 0; i < strlen(txBuffer); i++) {...

...завантажуємо перший передаваний символ у буфер передавача...

charBuffer = txBuffer[i];

...відбувається передача 8 байт поточного байта...

for (unsigned char i = 0; i < 8; i++) { //Формуємо фронт/срез

     if (charBuffer & (1 << 0)) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0);
     
     PULSE_DURATION(); //Тривалість логічного стану
     charBuffer >>=  1; //Зсув вправо на одну позицію
}

Ця процедура повторюється для кожного передаваного символу.

На сьогодні все! До нових зустрічей!!

ПРОЕКТ З ІСХОДНИМ КОДОМ І СИМУЛЯЦІЯ В PROTEUS у вкладенні.

Прикріплені файли:

Top