Цифрова послідовність. Передавач (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 у вкладенні.
Прикріплені файли:
- remote_control_ver_2.rar (82 Кб)