Тоже реализовал приём пакета, но по своему - аппаратно таймером, как и предлагал.
Использовал Таймер3 и ножку PA6.
На Кокосе проект, библиотека SPL.
Код:
#include "stm32f0xx.h"
#include "stm32f0xx_crc.h"
#include "stm32f0xx_dma.h"
#include "stm32f0xx_exti.h"
#include "stm32f0xx_flash.h"
#include "stm32f0xx_gpio.h"
#include "stm32f0xx_syscfg.h"
#include "stm32f0xx_i2c.h"
#include "stm32f0xx_pwr.h"
#include "stm32f0xx_rcc.h"
#include "stm32f0xx_rtc.h"
#include "stm32f0xx_spi.h"
#include "stm32f0xx_tim.h"
#include "stm32f0xx_usart.h"
#ifndef bool
#define bool unsigned char
#define true 1
#define false 0
#endif
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef timer3;
GPIO_InitTypeDef port;
TIM_ICInitTypeDef TIM_ICStructure;
void init_pwm_TIM3(void){
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
GPIO_StructInit(&port);
port.GPIO_Mode = GPIO_Mode_AF;//GPIO_Mode_IN;
port.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &port);
// GPIO_PinAFConfig(GPIOA,GPIO_Pin_6,GPIO_AF_1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_1);
TIM_TimeBaseStructInit(&timer3);
timer3.TIM_Prescaler = /*72*/(SystemCoreClock/1000000)-1;//считаем микросекунды
TIM_TimeBaseInit(TIM3, &timer3);
TIM_ICStructure.TIM_Channel = TIM_Channel_1;//первый канал
TIM_ICStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; // по заднему фронту
TIM_ICStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // прямо с ножки
TIM_ICStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // без делителя
TIM_ICStructure.TIM_ICFilter = 0; // без фильтра
// эта функция и включает режим PWM input - автоматически настраивает комплементарный канал
// правда в стандартной библиотеке работает на 1 и 2 канале, на 3 и 4 - не умеет
TIM_PWMIConfig(TIM3, &TIM_ICStructure);
/* Выбираем источник для триггера: вход 1 */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
/* По событию от триггера счётчик будет сбрасываться. */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
/* Включаем события от триггера */
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
// это третий канал, для таймаута. Таймаут 15мс, поскольку максимальный бит (старт) 13.5мс
TIM_OCInitTypeDef TIM_OCStructure;
TIM_OCStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCStructure.TIM_Pulse = 15000;
TIM_OC3Init(TIM3, &TIM_OCStructure);
/* Разрешаем таймеру генерировать прерывание по захвату */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
// и по таймауту третьего канала
TIM_ITConfig(TIM3, TIM_IT_CC3, DISABLE /*ENABLE*/);
TIM_ClearFlag(TIM3, TIM_FLAG_CC1);
TIM_ClearFlag(TIM3, TIM_FLAG_CC3);
/* Включаем таймер */
TIM_Cmd(TIM3, ENABLE);
//устанавливаем приоритет, долен быть больше 11 для корректной работы FreeRTOS
NVIC_SetPriority(TIM3_IRQn, 12);
// разрешаем прерывания
NVIC_EnableIRQ(TIM3_IRQn);
}
//Определим перечисляемый тип для событий ИК-приемника
enum Rx_Event {
NOT_EVENT, //нет событий
RX_COMPLETE, //принят пакет
RX_MESSAGE_COMPLETE,//принято сообщение
RX_ERROR //ошибка приема пакета
};
typedef enum Rx_Event trx_event; //Определим перечисляемый тип для событий ИК-приемника
enum damage_zone{
zone_4,
zone_3,
zone_2,
zone_1
};
typedef enum damage_zone TDamageZone;
#define ZONE_RX_BUFFER_SIZE 40 //Размер буффера приемника зон поражения
volatile uint8_t zone3_rx_buffer[ZONE_RX_BUFFER_SIZE]; //Буффер ИК-приемника
void set_zone_buffer_bit (TDamageZone zone, uint8_t index, bool value){
uint8_t byte_index;
uint8_t bit_index;
byte_index = index/8; //Определяем, в каком байте нахадится нужный бит
bit_index = index - (byte_index*8);//Определяем номер бита в байте
switch(zone)
{
case zone_1:
{
// if(value) zone1_rx_buffer[byte_index]|= (1<<(7-bit_index));
// else zone1_rx_buffer[byte_index] &= ~(1<<(7-bit_index));
}
break;
case zone_2:
{
// if(value) zone2_rx_buffer[byte_index]|= (1<<(7-bit_index));
// else zone2_rx_buffer[byte_index] &= ~(1<<(7-bit_index));
}
break;
case zone_3:
{
if(value) zone3_rx_buffer[byte_index]|= (1<<(7-bit_index));
else zone3_rx_buffer[byte_index] &= ~(1<<(7-bit_index));
}
break;
case zone_4:
{
// if(value) zone4_rx_buffer[byte_index]|= (1<<(7-bit_index));
// else zone4_rx_buffer[byte_index] &= ~(1<<(7-bit_index));
}
break;
}
}
enum recStatus{
REC_Idle,
REC_Recording,
REC_Captured
};
typedef enum recStatus TRecStatus;
volatile TRecStatus tim3_rec_state=REC_Idle;
volatile uint16_t tim3_ir_rx_count=0;
#define IR_RAW_BUFFER_SIZE 256 //размер буфера ИК-приемника
#define IR_START_BIT_DURATION 2400 // Длительность Старт-Бита (в микросекундах)
#define IR_ONE_BIT_DURATION 1200 // Длительность Бита, соотретствующего единичке (в микросекундах)
#define IR_ZERO_BIT_DURATION 600 // Длительность Бита, соотретствующего нулю (в микросекундах)
#define IR_SPACE_DURATION 600 // Длительность Бита, соотретствующего интервалу между битами (в микросекундах)
#define IR_TOL 20 //Допустимая погрешность при приеме ИК пакета (в процентах
volatile trx_event Zone3RxEvent;//события 3-ей зоны
// этот дефайн просто сравнивает значения с заданной точностью в процентах
#define checkVal(var,val,tol) (var>(val*(100-tol)/100) && var<(val*(100+tol)/100))
void TIM3_IRQHandler(void)//3-я зона
{
uint16_t cnt1, cnt2;
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
cnt1 = TIM_GetCapture1(TIM3);
cnt2 = TIM_GetCapture2(TIM3);
if (tim3_rec_state == REC_Recording)
{
if (tim3_ir_rx_count < IR_RAW_BUFFER_SIZE) {
if(tim3_ir_rx_count==0)//первым должен идти заголовок
{
if(checkVal(cnt2,IR_START_BIT_DURATION,IR_TOL))//проверяем заголовок на ошибку
{
tim3_ir_rx_count++;
}
else //заголовок "битый"
{
// запрещаем прерывания по переполнению третьего канала
TIM_ITConfig(TIM3, TIM_IT_CC3, /*ENABLE*/DISABLE);
tim3_rec_state = REC_Idle;
tim3_ir_rx_count=0;
}
}
else //заголовок уже получен, идет прием данных
{
// TIM3_IR_RX_RAW_BUFFER[tim3_ir_rx_count-1].Period=cnt1;
// TIM3_IR_RX_RAW_BUFFER[tim3_ir_rx_count-1].Pulse=cnt2;
if(checkVal(cnt2,IR_ONE_BIT_DURATION,IR_TOL)&&checkVal(cnt1,IR_ONE_BIT_DURATION+IR_SPACE_DURATION, IR_TOL))
{
set_zone_buffer_bit(zone_3,tim3_ir_rx_count-1,true);//это единица
tim3_ir_rx_count++;
}
else if (checkVal(cnt2, IR_ZERO_BIT_DURATION,IR_TOL)&&checkVal(cnt1,IR_ZERO_BIT_DURATION+IR_ZERO_BIT_DURATION,IR_TOL))
{
set_zone_buffer_bit(zone_3,tim3_ir_rx_count-1,false);//это ноль
tim3_ir_rx_count++;
} else {//ошибка
TIM_ITConfig(TIM3, TIM_IT_CC3, /*ENABLE*/DISABLE);
tim3_rec_state = REC_Idle;
tim3_ir_rx_count=0;
}
}
}
else {//слишком длинный пакет - ошибка
// запрещаем прерывания по переполнению третьего канала
TIM_ITConfig(TIM3, TIM_IT_CC3, /*ENABLE*/DISABLE);
tim3_rec_state = REC_Idle;
tim3_ir_rx_count=0;
}
}
if (tim3_rec_state == REC_Idle) {
//Пришел первый фронт, начинаем запись
//разрешаем прерывания по 3 каналу, предварительно очистив флаг
TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
TIM_ITConfig(TIM3, TIM_IT_CC3, ENABLE);
tim3_rec_state = REC_Recording;
// captCount = 0;
}
}//[if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) ]
if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET) {//если таймаут по приёму
TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
if (tim3_rec_state == REC_Recording) {
if((tim3_ir_rx_count==14)||(tim3_ir_rx_count==24))
{
cnt2 = TIM_GetCapture2(TIM3);
if(checkVal(cnt2,IR_ONE_BIT_DURATION,IR_TOL))
{
set_zone_buffer_bit(zone_3,tim3_ir_rx_count-1,true);//это единица
// tim3_ir_rx_count++;
}
else if (checkVal(cnt2, IR_ZERO_BIT_DURATION,IR_TOL))
{
set_zone_buffer_bit(zone_3,tim3_ir_rx_count-1,false);//это ноль
// tim3_ir_rx_count++;
} else {//ошибка
TIM_ITConfig(TIM3, TIM_IT_CC3, /*ENABLE*/DISABLE);
tim3_rec_state = REC_Idle;
tim3_ir_rx_count=0;
Zone3RxEvent=RX_ERROR;
// xSemaphoreGiveFromISR( xZone3Semaphore, &xHigherPriorityTaskWoken);
}
tim3_rec_state = REC_Captured;
if(tim3_ir_rx_count==14)Zone3RxEvent=RX_COMPLETE;
else Zone3RxEvent=RX_MESSAGE_COMPLETE;
// xSemaphoreGiveFromISR( xZone3Semaphore, &xHigherPriorityTaskWoken );
}
else {//ошибка
tim3_rec_state = REC_Idle;
Zone3RxEvent=RX_ERROR;
// xSemaphoreGiveFromISR( xZone3Semaphore, &xHigherPriorityTaskWoken );
}
// запрещаем прерывания по переполнению третьего канала
TIM_ITConfig(TIM3, TIM_IT_CC3, /*ENABLE*/DISABLE);
// tim5_rec_state = REC_Idle;
tim3_ir_rx_count=0;
//xSemaphoreGiveFromISR( xZone4Semaphore, &xHigherPriorityTaskWoken );
}
}
}
int main(void)
{
init_pwm_TIM3();
while(1)
{
}
}