UART на ATmega 32 пакетная структура команд

Речь в этом посте пойдет о том как увеличить помехозащищенность взаимодействия с микроконтроллером через UART’а. В моем прототипе bluetooth вертолета, в основе электроники которого была arduino, команды от BT-модуля BTM-112 передавались тоже своеобразными пакетами, однако очень урезаными и абсолютно восприимчивыми к помехам. Однако этого было достаточно для организации управления на начальном этапе. При переходе на ATmega 32 я решил использовать пакетную структуру команд управления.

Вид пакета выбирался из следующих соображений: для управлением вертолетом требуются 4-е  PWM выхода, соответственно нужно знать на какой из выходов идет команда и какую величину скважности ШИМ она несет, также необходимо отсечь помеху. Поэтому пакет имеет следующую структуру: Стартовый байт «A»|Длина|Величина ШИМ 1-го выхода|Величина ШИМ 2-го выхода|Величина ШИМ 3-его выхода|Величина ШИМ 4-ого выхода|Контрольная сумма (CRC) . Все составляющие пакета — это байты, контрольная сумма является суммой следующих элементов: CRC=Длина+Величина ШИМ 1+…+Величина ШИМ4 в байтах. По стартовому байту происходит синхронизация МК. Очевидно, что появляется необходимость использовать буфер, для хранения принятых по UART байт. В моем случае буфер — это обычный массив переменных типа unsigned char, для него также нужны указатели на текущий байт, на «хвост» и «голову». Инициализация выглядит следующим образом:

#define RxBfrSz 100           //размер буфера
unsigned char RxBfr[RxBfrSz]; //кольцевой (циклический) буфер
unsigned char RxBfrTail = 0;  //"указатель" хвоста буфера
unsigned char RxBfrHead = 0;  //"указатель" головы буфера
unsigned char RxBfrCntr = 0;  //счетчик символов
#define RxBfrSz 100 		  //размер буфера
unsigned char RxBfr[RxBfrSz]; //кольцевой (циклический) буфер
unsigned char RxBfrTail = 0;  //"указатель" хвоста буфера
unsigned char RxBfrHead = 0;  //"указатель" головы буфера
unsigned char RxBfrCntr = 0;  //счетчик символов

Так же необходимо описать процедуры работы с созданным буфером, а именно запись в буфер:

void PutCharBuf(unsigned char sym)
{
  if (RxBfrCntr < RxBfrSz){   //если в буфере еще есть место
      RxBfr[RxBfrTail] = sym;    //помещаем в него символ
      RxBfrCntr++;                    //инкрементируем счетчик символов
      RxBfrTail++;                           //и индекс хвоста буфера
      if (RxBfrTail == RxBfrSz) RxBfrTail = 0;
    }
}
void PutCharBuf(unsigned char sym)
{
  if (RxBfrCntr < RxBfrSz){   //если в буфере еще есть место
      RxBfr[RxBfrTail] = sym;    //помещаем в него символ
      RxBfrCntr++;                    //инкрементируем счетчик символов
      RxBfrTail++;                           //и индекс хвоста буфера
      if (RxBfrTail == RxBfrSz) RxBfrTail = 0;
    }
}

Получение символа:

unsigned char GetCharBuf(void)
{
   unsigned char sym = 0;
   if (RxBfrCntr > 0){          //если буфер не пустой
      sym = RxBfr[RxBfrHead];   //считываем символ из буфера
 
      cli();
      RxBfrCntr--;          //уменьшаем счетчик символов
      sei();
 
      RxBfrHead++;         //инкрементируем индекс головы буфера
      if (RxBfrHead == RxBfrSz) RxBfrHead = 0;
   }
   return sym;
}
unsigned char GetCharBuf(void)
{
   unsigned char sym = 0;
   if (RxBfrCntr > 0){          //если буфер не пустой
      sym = RxBfr[RxBfrHead];   //считываем символ из буфера

	  cli();
	  RxBfrCntr--;          //уменьшаем счетчик символов
      sei();

	  RxBfrHead++;         //инкрементируем индекс головы буфера
      if (RxBfrHead == RxBfrSz) RxBfrHead = 0;
   }
   return sym;
}

Очистка буфера

//Процедура очистки буфер
void FlushBuf(void)
{
    RxBfrTail = 0;
    RxBfrHead = 0;
    RxBfrCntr = 0;
}
//Процедура очистки буфер
void FlushBuf(void)
{
  	RxBfrTail = 0;
  	RxBfrHead = 0;
  	RxBfrCntr = 0;
}

Фактически происходит не очистка а процедура «забывания» указателей буфера, что в данном случае равносильно. Теперь необходимо разобраться с проверкой контрольной суммы. Осуществляется это в следующей функции:

unsigned char CalcCRC (unsigned char* buf, unsigned char k)
{
   char j=0;
   unsigned char i;
   for (i=k;i<(k+buf[k]-1);i++){
      j += buf[i];
   }
   return (j);
}
unsigned char CalcCRC (unsigned char* buf, unsigned char k)
{
   char j=0;
   unsigned char i;
   for (i=k;i<(k+buf[k]-1);i++){
      j += buf[i];
   }
   return (j);
}

Из массива буфера считываются n-1 элементов, n указано в первом элементе (длине) команды, то есть при желании можно несколько изменять структуру пакета команды, вводя дополнительные элементы. При этом функция проверки контрольной суммы не потребует изменения. Далее подсчитывается CRC и возвращается как значение функции. Далее задействуем все 4-е аппаратные выхода ATmega32, для этого необходимо инициализировать и настроить таймеры, отвечающие за соответствующие выводы. (Как настраивать PWM на выводе PB3(OCR0) описано в статье Управляем PWM на ATmega32 через UART, в конце этого поста будет полный листинг программы, там все настроено и даже написано на какие параметры). А сейчас функция обработки полученного пакета команды:

//Функция обработки команды
void GetVal (void)
{
    unsigned char i, Val_PWM;
    if (RxBfrCntr >= 6) {
        for (i=0;i<=RxBfrCntr;i++) {
        //  Проверяем есть ли в числе принятых стартовый байт
            if (RxBfr[i]==65 && RxBfrCntr-i>=6) {
                //Проверка контрольной суммы
                if (CalcCRC (RxBfr, i+1) == RxBfr[i+1+RxBfr[i+1]-1]) {
                    PWM_A1 = RxBfr[i+2];
                    PWM_A2 = RxBfr[i+3];
                    PWM_B = RxBfr[i+4];
                    PWM_C = RxBfr[i+5];
                }
             FlushBuf();
            }
        }
        // Возвращаем последовательность обратно и стираем буфер
        for(i=0;i<=RxBfr[0]-1;i++) {
                put(RxBfr[i]);
        }
        put('\r');
           put('\n');
    }
}
//Функция обработки команды
void GetVal (void)
{
	unsigned char i, Val_PWM;
	if (RxBfrCntr >= 6) {
		for (i=0;i<=RxBfrCntr;i++) {
		//	Проверяем есть ли в числе принятых стартовый байт
			if (RxBfr[i]==65 && RxBfrCntr-i>=6) {
				//Проверка контрольной суммы
				if (CalcCRC (RxBfr, i+1) == RxBfr[i+1+RxBfr[i+1]-1]) {
					PWM_A1 = RxBfr[i+2];
					PWM_A2 = RxBfr[i+3];
					PWM_B = RxBfr[i+4];
					PWM_C = RxBfr[i+5];
				}
			 FlushBuf();
			}
		}
		// Возвращаем последовательность обратно и стираем буфер
		for(i=0;i<=RxBfr[0]-1;i++) {
				put(RxBfr[i]);
		}
		put('\r');
           put('\n');
	}
}

В этой функции мы проверяем полученные символы, и если среди них есть стартовый байт и в буфере, после него, уже накопилось число элементов равное или большее длине команды, производим подсчет и проверку CRC. После чего, при совпадении контрольной суммы изменяем величину ШИМ на выводах МК. При этом буфер мы наполняем в обработчике прерывания по приходу символа по UART, записываем его и быстро сваливаем с прерывания,  дабы не держать в «подвешенном состоянии» выполнение основной программы:

ISR(USART_RXC_vect)
{
    unsigned char data;
    data = UDR;
    // помещаем принятый символ в буфер
    PutCharBuf(data);
}
ISR(USART_RXC_vect)
{
	unsigned char data;
	data = UDR;
	// помещаем принятый символ в буфер
	PutCharBuf(data);
}

Программа для МК написана, как и говорил полный код:

#include <avr/io.h>//библиотека ввода/вывода
#include <stdio.h>//Библиотека функций
#include <util/delay.h>//Библиотека функций задержки
#include <avr/interrupt.h> //Библиотека прерываний
 
// Порты вывода
#define PORT_PWM_B DDRB  // порт МК
#define PORT_PWM_D DDRD  // порт МК 
 
#define PIN_PWM_A1 3     // вывод порта B - PB3
#define PIN_PWM_A2 4     // вывод порта B - PD4
#define PIN_PWM_B  5     // вывод порта B - PD5
#define PIN_PWM_C  7     // вывод порта B - PD7
 
#define PWM_A1 OCR0     // вывод порта B - PB3
#define PWM_A2 OCR1B     // вывод порта B - PD4
#define PWM_B  OCR1A     // вывод порта B - PD5
#define PWM_C  OCR2     // вывод порта B - PD7
 
/* буфер-----------------------------------------------------------*/
#define RxBfrSz 100           //размер буфера
unsigned char RxBfr[RxBfrSz]; //кольцевой (циклический) буфер
unsigned char RxBfrTail = 0;  //"указатель" хвоста буфера
unsigned char RxBfrHead = 0;  //"указатель" головы буфера
unsigned char RxBfrCntr = 0;  //счетчик символов
 
//Программа инициализации USART
void USART_Init( unsigned long baud, unsigned long SsFrqnc )
{
    #define XTAL SsFrqnc
    #define baudrate baud
    #define bauddivider (XTAL/(16*baudrate)-1)
    #define HI(x) ((x)>>8)
    #define LO(x) ((x)& 0xFF)
 
    UBRRL = LO(bauddivider);
    UBRRH = HI(bauddivider);
    UCSRA = 0;
    UCSRB = 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE;
    UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1;
 
    sei();                   //Разрешение глобальных прерываний
 
}
 
//Програма инициализации ШИМ
void init_pwm (void)
{
    /* Задествуем аппаратные ШИМ на таймерах 0-2
    настраиваем 8-ми битный таймер*/
    TCCR0 = 1<<WGM00|1<<COM01|1<<WGM01|1<<CS02;// предделитель 256
 
    /*Настраиваем второй 16-и битный таймер*/
    TCCR1A = 1<<COM1A1|1<<COM1B1|1<<WGM10;
    TCCR1B = 1<<WGM12|1<<CS12;// предделитель 256
 
    //Настраиваем третий 8-ми таймер
    TCCR2 = 1<<WGM20|1<<COM21|1<<WGM21|1<<CS22|1<<CS21;// предделитель 256
 
    // Начальные значения ШИМ на выводах МК
    PWM_A1 = 50;
    PWM_A2 = 150;
    PWM_B  = 200;
    PWM_C  = 250;
 
}
 
//Запись в UART:
void put(unsigned char data) { // Put a char
    while (!(UCSRA & (1<<UDRE)));
    UDR = data;
}
 
//Процедура очистки буфера
void FlushBuf(void)
{
    RxBfrTail = 0;
    RxBfrHead = 0;
    RxBfrCntr = 0;
}
 
//Процедура пополнения буфера символом
void PutCharBuf(unsigned char sym)
{
  if (RxBfrCntr < RxBfrSz){   //если в буфере еще есть место
      RxBfr[RxBfrTail] = sym;    //помещаем в него символ
      RxBfrCntr++;                    //инкрементируем счетчик символов
      RxBfrTail++;                           //и индекс хвоста буфера
      if (RxBfrTail == RxBfrSz) RxBfrTail = 0;
    }
}
 
//взять символ из буфера
unsigned char GetCharBuf(void)
{
   unsigned char sym = 0;
   if (RxBfrCntr > 0){                            //если буфер не пустой
      sym = RxBfr[RxBfrHead];              //считываем символ из буфера
 
      cli();
      RxBfrCntr--;                                   //уменьшаем счетчик символов
      sei();
 
      RxBfrHead++;                                  //инкрементируем индекс головы буфера
      if (RxBfrHead == RxBfrSz) RxBfrHead = 0;
   }
   return sym;
}
 
//Функция проверки контрольной суммы
unsigned char CalcCRC (unsigned char* buf, unsigned char k)
{
   char j=0;
   unsigned char i;
   for (i=k;i<(k+buf[k]-1);i++){
      j += buf[i];
   }
   return (j);
 
}
 
//Функция обработки команды
void GetVal (void)
{
    unsigned char i, Val_PWM;
    if (RxBfrCntr >= 6) {
        for (i=0;i<=RxBfrCntr;i++) {
        //  Проверяем есть ли в числе принятых стартовый байт
            if (RxBfr[i]==65 && RxBfrCntr-i>=6) {
                //Проверка контрольной суммы
                if (CalcCRC (RxBfr, i+1) == RxBfr[i+1+RxBfr[i+1]-1]) {
 
                    PWM_A1 = RxBfr[i+2];
                    PWM_A2 = RxBfr[i+3];
                    PWM_B = RxBfr[i+4];
                    PWM_C = RxBfr[i+5];
                }
             FlushBuf();
            }
 
        }
 
        // Возвращаем последовательность обратно и стираем буфер
        for(i=0;i<=RxBfr[0]-1;i++) {
                put(RxBfr[i]);
        }
        put('\r\n');
 
    }
 
}
 
/*--Прерывания--------------------------------------------------*/
 
// Прерывание по приходу байта в USART
ISR(USART_RXC_vect)
{
    unsigned char data;
    data = UDR;
    // помещаем принятый символ в буфер
    PutCharBuf(data);
}   
 
/*--Основная программа-----------------------------------------------*/
int main(void)
{ 
 
 PORT_PWM_B = 1<< PIN_PWM_A1;  //Инициализация порта PB3 как выхода
 PORT_PWM_D = 1<<PIN_PWM_A2|1<<PIN_PWM_B|1<<PIN_PWM_C; //Инициализация портов PD4, PD5, PD7 как выходов
 init_pwm();                //Вызов процедуры инициализации PWM
 USART_Init(19200,16000000); //Вызов процедуры инициализации USART на скорости 19200б/с
 
 while (1)
  {
     GetVal();
  }
 
 return 1;
}
#include <avr/io.h>//библиотека ввода/вывода
#include <stdio.h>//Библиотека функций
#include <util/delay.h>//Библиотека функций задержки
#include <avr/interrupt.h> //Библиотека прерываний

// Порты вывода
#define PORT_PWM_B DDRB  // порт МК
#define PORT_PWM_D DDRD  // порт МК 

#define PIN_PWM_A1 3     // вывод порта B - PB3
#define PIN_PWM_A2 4     // вывод порта B - PD4
#define PIN_PWM_B  5     // вывод порта B - PD5
#define PIN_PWM_C  7     // вывод порта B - PD7

#define PWM_A1 OCR0     // вывод порта B - PB3
#define PWM_A2 OCR1B     // вывод порта B - PD4
#define PWM_B  OCR1A     // вывод порта B - PD5
#define PWM_C  OCR2     // вывод порта B - PD7

/* буфер-----------------------------------------------------------*/
#define RxBfrSz 100 		  //размер буфера
unsigned char RxBfr[RxBfrSz]; //кольцевой (циклический) буфер
unsigned char RxBfrTail = 0;  //"указатель" хвоста буфера
unsigned char RxBfrHead = 0;  //"указатель" головы буфера
unsigned char RxBfrCntr = 0;  //счетчик символов

//Программа инициализации USART
void USART_Init( unsigned long baud, unsigned long SsFrqnc )
{
	#define XTAL SsFrqnc
	#define baudrate baud
	#define bauddivider (XTAL/(16*baudrate)-1)
	#define HI(x) ((x)>>8)
	#define LO(x) ((x)& 0xFF)

	UBRRL = LO(bauddivider);
	UBRRH = HI(bauddivider);
	UCSRA = 0;
	UCSRB = 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE;
	UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1;

	sei();					 //Разрешение глобальных прерываний

}

//Програма инициализации ШИМ
void init_pwm (void)
{
 	/* Задествуем аппаратные ШИМ на таймерах 0-2
  	настраиваем 8-ми битный таймер*/
  	TCCR0 = 1<<WGM00|1<<COM01|1<<WGM01|1<<CS02;// предделитель 256

  	/*Настраиваем второй 16-и битный таймер*/
  	TCCR1A = 1<<COM1A1|1<<COM1B1|1<<WGM10;
  	TCCR1B = 1<<WGM12|1<<CS12;// предделитель 256

  	//Настраиваем третий 8-ми таймер
  	TCCR2 = 1<<WGM20|1<<COM21|1<<WGM21|1<<CS22|1<<CS21;// предделитель 256

  	// Начальные значения ШИМ на выводах МК
  	PWM_A1 = 50;
  	PWM_A2 = 150;
  	PWM_B  = 200;
  	PWM_C  = 250;

}

//Запись в UART:
void put(unsigned char data) { // Put a char
	while (!(UCSRA & (1<<UDRE)));
	UDR = data;
}

//Процедура очистки буфера
void FlushBuf(void)
{
  	RxBfrTail = 0;
  	RxBfrHead = 0;
  	RxBfrCntr = 0;
}

//Процедура пополнения буфера символом
void PutCharBuf(unsigned char sym)
{
  if (RxBfrCntr < RxBfrSz){   //если в буфере еще есть место
      RxBfr[RxBfrTail] = sym;    //помещаем в него символ
      RxBfrCntr++;                    //инкрементируем счетчик символов
      RxBfrTail++;                           //и индекс хвоста буфера
      if (RxBfrTail == RxBfrSz) RxBfrTail = 0;
    }
}

//взять символ из буфера
unsigned char GetCharBuf(void)
{
   unsigned char sym = 0;
   if (RxBfrCntr > 0){                            //если буфер не пустой
      sym = RxBfr[RxBfrHead];              //считываем символ из буфера

	  cli();
	  RxBfrCntr--;                                   //уменьшаем счетчик символов
      sei();

	  RxBfrHead++;                                  //инкрементируем индекс головы буфера
      if (RxBfrHead == RxBfrSz) RxBfrHead = 0;
   }
   return sym;
}

//Функция проверки контрольной суммы
unsigned char CalcCRC (unsigned char* buf, unsigned char k)
{
   char j=0;
   unsigned char i;
   for (i=k;i<(k+buf[k]-1);i++){
      j += buf[i];
   }
   return (j);

}

//Функция обработки команды
void GetVal (void)
{
	unsigned char i, Val_PWM;
	if (RxBfrCntr >= 6) {
		for (i=0;i<=RxBfrCntr;i++) {
		//	Проверяем есть ли в числе принятых стартовый байт
			if (RxBfr[i]==65 && RxBfrCntr-i>=6) {
				//Проверка контрольной суммы
				if (CalcCRC (RxBfr, i+1) == RxBfr[i+1+RxBfr[i+1]-1]) {

					PWM_A1 = RxBfr[i+2];
					PWM_A2 = RxBfr[i+3];
					PWM_B = RxBfr[i+4];
					PWM_C = RxBfr[i+5];
				}
			 FlushBuf();
			}

		}

		// Возвращаем последовательность обратно и стираем буфер
		for(i=0;i<=RxBfr[0]-1;i++) {
				put(RxBfr[i]);
		}
		put('\r\n');

	}

}

/*--Прерывания--------------------------------------------------*/

// Прерывание по приходу байта в USART
ISR(USART_RXC_vect)
{
	unsigned char data;
	data = UDR;
	// помещаем принятый символ в буфер
	PutCharBuf(data);
}	

/*--Основная программа-----------------------------------------------*/
int main(void)
{ 

 PORT_PWM_B = 1<< PIN_PWM_A1;  //Инициализация порта PB3 как выхода
 PORT_PWM_D = 1<<PIN_PWM_A2|1<<PIN_PWM_B|1<<PIN_PWM_C; //Инициализация портов PD4, PD5, PD7 как выходов
 init_pwm();				//Вызов процедуры инициализации PWM
 USART_Init(19200,16000000); //Вызов процедуры инициализации USART на скорости 19200б/с

 while (1)
  {
	 GetVal();
  }

 return 1;
}

Proteus’овским терминалом будет достаточно сложно  проверить этот код, поэтому я решил тестить все сразу в железе.

Основные моменты с ШИМ и UART’от были уже отлажены, поэтому особых проблем ничто не предвещало. Собственно, необходимо теперь написать мини-программу для тестов. Я сделал это с помощью processing, ибо показалось, что так будет быстрее.) Код здесь тоже не сложный. В окне программы расположены четыре слайдера которые и управляют скважностью PWM выводов МК. В текстовом поле , начинающемся с «In:» отображаются принятые от ATmega строки.

Прошил прогу в МК, благо мне теперь это не составляет труда благодаря загрузчику и bluetooth модулю. На пару выводов с ШИМ подключил через резисторы светодиоды и запустив приложение по управлял их яркостью, убедившись в работоспособности кода:

Код для приложения на processing’е представлен ниже:

// ипортируем библиотеки
import controlP5.*;
import cc.arduino.*;
import processing.serial.*;
 
// инициализируем объекты и переменные
ControlP5 controlP5;
Serial port; // создаем объект класса COM порта
 
// показания слайдеров яркости светодиодов
int PwrSldr_A1 = 0;
int PwrSldr_A2 = 0;
int PwrSldr_B = 0;
int PwrSldr_C = 0;
 
/*Функция передачи команды вида
Стартовый айт"A"|Длина|ВеличинаPWM1...Длина|ВеличинаPWM4|Контрольная сумма|*/
void comand_put() {
  byte CRC;
  port.write("A");
  port.write(6);
  port.write(byte(PwrSldr_A1));
  port.write(byte(PwrSldr_A2));
  port.write(byte(PwrSldr_B));
  port.write(byte(PwrSldr_C));
  CRC = byte(6+PwrSldr_A1+PwrSldr_A2+
  PwrSldr_B+PwrSldr_C);
  port.write(CRC);
}
 
/*Функция приема ответа  */
String answer_get() {
  String decoder = "";
  while (port.available() > 0) {
   // decoder = port.readStringUntil('\n');
    decoder = port.readString();
  }
  // текст
  fill(255);
  text("In: "+decoder, 45, 100);
  return decoder;
}
 
// функция рисования индикаторов яркости
void id_light() {
  rectMode(CORNER);
  //Индикатор PWM_A1
  fill(PwrSldr_A1);
  rect(45, 180, 20, 20);
  stroke(255);
  rect(45, 180, 20, 20);
  //Индикатор PWM_A1
  fill(PwrSldr_A2);
  rect(125, 180, 20, 20);
  stroke(255);
  rect(125, 180, 20, 20);
  //Индикатор PWM_A1
  fill(PwrSldr_B);
  rect(205, 180, 20, 20);
  stroke(255);
  rect(205, 180, 20, 20);
  //Индикатор PWM_A1
  fill(PwrSldr_C);
  rect(285, 180, 20, 20);
  stroke(255);
  rect(285, 180, 20, 20);
 
}
 
void setup() {
  size(400,400);
  // создаем экземпляр объекта порт и ControlP5
  port = new Serial(this, "COM4", 19200);
  controlP5 = new ControlP5(this);
 
  // вертикальные слайдеры яркости
  controlP5.addSlider("PwrSldr_A1",0,100,0,50,210,10,100);
  controlP5.addSlider("PwrSldr_A2",0,100,0,130,210,10,100);
  controlP5.addSlider("PwrSldr_B",0,255,0,210,210,10,100);
  controlP5.addSlider("PwrSldr_C",0,255,0,290,210,10,100);
}
 
void draw() {
  background(0); // фон
 
  PFont font; // параметры текста
  font = loadFont("TimesNewRomanPSMT-24.vlw");
  textFont(font, 18); 
 
  //Рисуем индикаторы яркости
  id_light();
 
  //Читаем порт
  answer_get();
 
  //Отправляем значения яркости каждого светодиода
  comand_put();
 
  // задержка, чтобы не захламлять буфер
  delay(30);
 
}
// ипортируем библиотеки
import controlP5.*;
import cc.arduino.*;
import processing.serial.*;

// инициализируем объекты и переменные
ControlP5 controlP5;
Serial port; // создаем объект класса COM порта

// показания слайдеров яркости светодиодов
int PwrSldr_A1 = 0;
int PwrSldr_A2 = 0;
int PwrSldr_B = 0;
int PwrSldr_C = 0;

/*Функция передачи команды вида
Стартовый айт"A"|Длина|ВеличинаPWM1...Длина|ВеличинаPWM4|Контрольная сумма|*/
void comand_put() {
  byte CRC;
  port.write("A");
  port.write(6);
  port.write(byte(PwrSldr_A1));
  port.write(byte(PwrSldr_A2));
  port.write(byte(PwrSldr_B));
  port.write(byte(PwrSldr_C));
  CRC = byte(6+PwrSldr_A1+PwrSldr_A2+
  PwrSldr_B+PwrSldr_C);
  port.write(CRC);
}

/*Функция приема ответа  */
String answer_get() {
  String decoder = "";
  while (port.available() > 0) {
   // decoder = port.readStringUntil('\n');
    decoder = port.readString();
  }
  // текст
  fill(255);
  text("In: "+decoder, 45, 100);
  return decoder;
}

// функция рисования индикаторов яркости
void id_light() {
  rectMode(CORNER);
  //Индикатор PWM_A1
  fill(PwrSldr_A1);
  rect(45, 180, 20, 20);
  stroke(255);
  rect(45, 180, 20, 20);
  //Индикатор PWM_A1
  fill(PwrSldr_A2);
  rect(125, 180, 20, 20);
  stroke(255);
  rect(125, 180, 20, 20);
  //Индикатор PWM_A1
  fill(PwrSldr_B);
  rect(205, 180, 20, 20);
  stroke(255);
  rect(205, 180, 20, 20);
  //Индикатор PWM_A1
  fill(PwrSldr_C);
  rect(285, 180, 20, 20);
  stroke(255);
  rect(285, 180, 20, 20);

}

void setup() {
  size(400,400);
  // создаем экземпляр объекта порт и ControlP5
  port = new Serial(this, "COM4", 19200);
  controlP5 = new ControlP5(this);

  // вертикальные слайдеры яркости
  controlP5.addSlider("PwrSldr_A1",0,100,0,50,210,10,100);
  controlP5.addSlider("PwrSldr_A2",0,100,0,130,210,10,100);
  controlP5.addSlider("PwrSldr_B",0,255,0,210,210,10,100);
  controlP5.addSlider("PwrSldr_C",0,255,0,290,210,10,100);
}

void draw() {
  background(0); // фон

  PFont font; // параметры текста
  font = loadFont("TimesNewRomanPSMT-24.vlw");
  textFont(font, 18); 

  //Рисуем индикаторы яркости
  id_light();

  //Читаем порт
  answer_get();

  //Отправляем значения яркости каждого светодиода
  comand_put();

  // задержка, чтобы не захламлять буфер
  delay(30);

}
Запись опубликована в рубрике AVR. Добавьте в закладки постоянную ссылку.

         
Подписаться на новые статьи блога:

2 комментария: UART на ATmega 32 пакетная структура команд

  1. Nemo говорит:

    Можно сделать структуру с полями:
    unsigned char RxBfr[RxBfrSz]; //кольцевой (циклический) буфер
    unsigned char RxBfrTail = 0; //»указатель» хвоста буфера
    unsigned char RxBfrHead = 0; //»указатель» головы буфера
    unsigned char RxBfrCntr = 0; //счетчик символов

    будет удобней.

    typedef struct
    {

    unsigned char BfrTail ;
    ….
    } FIFO;
    FIFO Rx;

    и писать/читать значения.
    Rx.BfrTail = some data;

    • Delirium говорит:

      Конечно можно все тут заоптимизировать и сделать удобнее и нагляднее. Попробую этот способ. Спасибо!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.