На этом уроке мы с Вами разберём программную реализацию интерфейса передатчика с цифровой, байт ориентированной последовательности на микроконтроллере 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 Кб)
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация