2.1 38KHz载波产生
常用的38KHz载波的产生方法有455KHz晶振分频法、时基电路搭建法、微控制器PWM模块产生法。为减少硬件规模、缩减成本,故由STM32的定时器输出PWM波,得到占空比1:3的红外载波。
STM32 的定时器分为高级定时器(TIMER1、TIMER2)、基本定时器(TIMER6、TIMER7) 和通用定时器(TIMER2~ TIMER5),具有非常强大的功能。其中通用定时器可以用于输入捕获、输出比较和PWM等,通过定时器的预分频器和RCC时钟控制预分频器,脉冲长度和 波形周期能够在几个微秒到毫秒间进行调整。此外,每个通用定时器都是完全独立,不曾共享任何资源。
本模块使用定时器TIM2的通道CH1输出占空比1:3的载波信号。操作流程图如下图所示:
程序代码如下:
/********************************************************************
* Function Name : TIM2_PWM_Init(u16 arr,u16 psc)
* Function : TIM2的通道CH1的PWM模式初始化
* parameter : arr - 自动重装值
psc - 时钟预分频数
* Description : 频率f = 72M/[(psc+1)*(arr+1)]
* Return : void
*********************************************************************/
void TIM2_PWM_Init(u16 arr,u16 psc)
{
/* 初始化结构体定义 */
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* 使能相应端口的时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO外设时钟
/* GPIOA.0初始化 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // TIM2 CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // PA.0 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
/* TIM2 初始化*/
TIM_TimeBaseInitStructure.TIM_Period = arr; //下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseInitStructure.TIM_Prescaler = psc; //作为TIMx时钟频率除数的预分频值
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; //时钟分割:TDTS = Tck_tim
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
/* 定时器TIM2 Ch1 PWM模式初始化 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM PWM1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
//TIM_OCInitStructure.TIM_Pulse = (arr+1)/2; //占空比 50%
TIM_OCInitStructure.TIM_Pulse = (arr+1)/3; //占空比1:3
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性:TIM输出比较极性高
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
/* 使能TIM2在CCR1上的预装载寄存器 */
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
/* 使能定时器 */
TIM_Cmd(TIM2, ENABLE);
}
示波器(RIGOL DG1102E)查看38KHz载波信号的波形,如下图所示:
2.2 按键设计
设置STM32的GPIO口为输入模式,通过读取IO口状态,判断是否有按键按下。为避免干扰产生一些误操作,在检测到电平变化后延时一段时间,再重新读取IO口状态。
本模块设置了5个独立按键的接口,实现流程图如下图所示:
程序代码如下:
/********************************************************************
* Function Name : KEY_Init(void)
* Function : 按键端口初始化
* parameter : void
* Description : void
* Return : void
*********************************************************************/
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Enable PORTA clock
/* 初始化KEY1-->KEY5 上拉输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 |GPIO_Pin_4 |GPIO_Pin_5 |
GPIO_Pin_6 |GPIO_Pin_7; // Config port
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU; // Input pull-up
GPIO_Init(GPIOA, &GPIO_InitStructure); // Init GPIOA3~7
}
/********************************************************************
* Function Name : KEY_Scan(u8 mode)
* Function : 按键扫描
* parameter : mode - 0,不支持连续按;1,支持连续按
* Return : 0 - 没有任何按键按下
1 - KEY0按下
2 - KEY1按下
*********************************************************************/
u8 KEY_Scan(u8 mode)
{
static u8 key_up = 1;
if(mode) key_up=1;
if(key_up&&(KEY1==0||KEY2==0|KEY3==0|KEY4==0|KEY5==0)){ // key down
delay_ms(10); // eliminate debouncing
key_up = 0;
if(KEY1==0) return VOL_UP;
else if(KEY2==0) return VOL_DOWN;
else if(KEY3==0) return CH_UP;
else if(KEY4==0) return CH_DOWN;
else if(KEY5==0) return PWR_ON;
}
else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1&&KEY5==1){
key_up = 1;
}
return 0;// 无按键按下
}
2.3 STM32接收红外信号并测其脉宽
向量中断控制器(NVIC)与Cortex-M3内核的逻辑紧密耦合、相互交融,共同完成对中断的控制。
STM32有两个优先级概念—抢占式优先级和响应优先级,响应优先级又被称为亚优先级或副优先级,STM32的每个中断源都需要指定这两种优先级。
高抢占式优 先级的中断可以在具有低抢占式优先级的中断处理中被响应,即所谓的中断嵌套。当两个中断源的抢占式优先级相同时,两者间就没有嵌套关系,后到来的中断就需 要等待前一个中断处理完后才能被响应;若两个中断同时到达,中断控制器会根据它们响应优先级的高低决定优先处理哪一个;若两个中断的抢占式优先级和响应优 先级都相同,则根据它们在中断表中的排列顺序决定两者的处理先后。
每个中断源都需要指定抢占式优先级和响应优先级,这就需要相应的寄存器记录每个中断的优先级。Cortex-M3中定义8比特来设置中断优先级,故有8中分配方式,优先级分组如下:
1)所有8位都用来指定响应优先级;
2)最高1位指定抢占式优先级,最低7位指定响应优先级;
3)最高2位指定抢占式优先级,最低6位指定响应优先级;
4)最高3位指定抢占式优先级,最低5位指定响应优先级;
5)最高4位指定抢占式优先级,最低4位指定响应优先级;
6)最高5位指定抢占式优先级,最低3位指定响应优先级;
7)最高6位指定抢占式优先级,最低2位指定响应优先级;
8)最高7位指定抢占式优先级,最低1位指定响应优先级;
在STM32中指定中断优先级的寄存器减少到4位,可以通过固件库函数
NVIC_PriorityGroupConfig()进行选择,该函数的参数有5个,如下:
1)NVIC_PriorityGroup_0: 选择第0组;
2)NVIC_PriorityGroup_1: 选择第1组;
3)NVIC_PriorityGroup_2: 选择第2组;
4)NVIC_PriorityGroup_3: 选择第3组;
5)NVIC_PriorityGroup_4: 选择第4组。
EXTI,即外部中断/事件控制器,由19个产生事件/中断要求的边沿检测器组成,每个输入线可以被独立的配置为脉冲或挂起和对应的触发事件(上升沿、下降沿、双边沿),每个输入线都能够被独立的屏蔽掉。EXTI控制器主要特点如下:
1)支持多达19个中断/事请求
2)每个中断/事件都有独立的触发和屏蔽;
3)每个中断线都有专用的状态位;
STM32外部中断实现红外脉宽测量的原理为:检测到红外脉冲下降沿后,进入中断处理函数,然后分别对红外信号的高和低电平进行测量,并把测量的结果的暂存到一个临时数组中。软件流程图如下图所示:
在硬件仿真下点全速运行的按钮,然后用红外设备对着红外一体接收管按下按键,在Watch1窗口查看数组中数据是否在协议规定范围内。然后把该数据调制后发送给接收设备,看它和原始红外设备发送码数据是否一致。接收到的脉宽数据如下图所示: