在上一贴,我们进行了基本的程序架构的设置,接下来就是LED的控制了。
言归正传,点灯在各位大神的手里已经已经玩出花样了,芯源的测试板板载可控的LED只有两个,想想都可以做什么呢?循环灯、同亮同灭、循环闪烁、再加上一个高级点的呼吸灯。
接下来重点分析一下实现这些功能够需要什么?
循环灯、同亮同灭、循环闪烁基本操作就是IO口的翻转,不过期间需要延时功能,一种是原地等待,一种是定时器定时,这里选择定时器定时,相对来说定时器定时精准;
呼吸灯涉及到的就是定时器的PWM输出了,查阅数据手册发现:
PB8/9可以连接通用定时器(G tiM) ,可以产生输出波形(输出比较和PWM)。
接下来就是模式切换的功能分析,一种是自动模式切换,设计到的就是定时功能,一种是按键操作功能,设计到的就是按键采集,可以使用轮询的方法,也可以使用外部中断的方式,芯源的所有IO口都可以配置为外部中断。
这里我们把灯操作可能设计到的资源需求都分析出来,接下来就让我们一起一步一步实现他们。
对于IO口的数字输出功能不在进行赘述,主要讲一下外部中断功能,GPIO 在设置为数字输入模式时,可作为外部中断信号源,中断的信号源可以设置为高电平、低电平、上升沿、下降沿4 种,结合 开发板的原理图,当按键按下时会产生一个下降沿,故选择下降沿方式作为外部中断的触发方式,同时中断数字滤波器可对引脚上的输入信号进行数字滤波,实现防抖功能,注意同一组引脚使用相同的滤波时钟。对于外部中断一般都是使用高优先级,芯片默认的优先级即为高优先级。
初始化代码如下:
- //******************************************************************************
- // 函数名称 : port_EXIT_init
- // 函数描述 : 单片机的外部中断初始化
- // 输入参数 :
- // 参数描述 :
- // 输出参数 : 无
- // 返回值 : 无
- //******************************************************************************
- void port_EXIT_init(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- __RCC_GPIOA_CLK_ENABLE();
-
- GPIO_InitStruct.IT = GPIO_IT_FALLING;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pins = GPIO_PIN_1|GPIO_PIN_2;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_Init(CW_GPIOA,&GPIO_InitStruct);
-
- //配置中断滤波
- GPIO_ConfigFilter(CW_GPIOA,bv1,GPIO_FLTCLK_RC150K);
-
- //清除PA00中断标志并使能NVIC
- GPIOA_INTFLAG_CLR(bv1| bv2);
- NVIC_EnableIRQ(GPIOA_IRQn);
- }
复制代码
接下来就是定时器的初始化配置,需要配置GTIM1的CH3和CH4为PWM输出,GTIM2实现10ms定时功能。
GTIM2代码如下:
- //******************************************************************************
- //* 函数名称 : GTIM2PWM_init
- //* 函数描述 : 定时器2的配置为ms级定时器
- //* 输入参数 : Period:ms
- //* 参数描述 : 对应 定时器引脚初始化及配置
- //* 输出参数 : 无
- //* 返回值 : 无
- //******************************************************************************
- void GTIM2_init(uint16_t Period)
- {
- GTIM_InitTypeDef GTIM_InitStruct;
- BTIM_TimeBaseInitTypeDef BTIM_InitStruct;;
-
- __RCC_BTIM_CLK_ENABLE();
- __RCC_GTIM2_CLK_ENABLE();
-
- __disable_irq();
- NVIC_EnableIRQ(GTIM2_IRQn);
- __enable_irq();
-
- GTIM_InitStruct.Mode = GTIM_MODE_COUNTER;
- GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
- GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV1;
- GTIM_InitStruct.ReloadValue = Period-1;//定时ms
- GTIM_InitStruct.ToggleOutState = DISABLE;
- GTIM_TimeBaseInit(CW_GTIM2, >IM_InitStruct);
-
- GTIM2_ITRConfig(ITR_SOURCE_BTIM1);
-
- BTIM_InitStruct.BTIM_Mode = BTIM_Mode_TIMER;
- BTIM_InitStruct.BTIM_OPMode = BTIM_OPMode_Repetitive;
- BTIM_InitStruct.BTIM_Period = 999;
- BTIM_InitStruct.BTIM_Prescaler = BTIM_PRS_DIV64;
- BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
-
- GTIM_ITConfig(CW_GTIM2, GTIM_IT_OV, ENABLE);
- GTIM_Cmd(CW_GTIM2, ENABLE);
- BTIM_Cmd(CW_BTIM1, ENABLE);
-
- }
复制代码
每Period ms会产生一个定时中断,首先通过BTIM1进行第一级分频,产生的输出作为GTIM2的输入,这样64M通过BTIM_PRS_DIV64分频后每1ms产生一个输出,同时GTIM2根据设置Period ms产生一个中断。
GTIM1产生PWM初始化代码:
- //******************************************************************************
- //* 函数名称 : GTIM1PWM_init
- //* 函数描述 : 定时器1的配置输出PWM
- //* 输入参数 :
- //* 参数描述 : 对应 定时器引脚初始化及配置
- //* 输出参数 : 无
- //* 返回值 : 无
- //******************************************************************************
- void GTIM1PWM_init(uint16_t Period)
- {
-
- GPIO_InitTypeDef GPIO_InitStruct;
- GTIM_InitTypeDef GTIM_InitStruct;
-
- __RCC_GPIOB_CLK_ENABLE();
- __RCC_GTIM1_CLK_ENABLE();
- //set PB08 / PB09 as outupt with pur / int = none
- GPIO_InitStruct.Pins = GPIO_PIN_8 | GPIO_PIN_9;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.IT = GPIO_IT_NONE;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- // PB08_AFx_GTIM1CH3();
- // PB09_AFx_GTIM1CH4();
- GPIO_Init(CW_GPIOB,&GPIO_InitStruct);
-
- GTIM_InitStruct.Mode = GTIM_MODE_TIME;
- GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
- GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV64; // DCLK = PCLK / 64 = 64MHz/64 = 1MHz
- GTIM_InitStruct.ReloadValue = 1000000/Period-1;//PWM为200Hz (1/200)/(1/1M)
- GTIM_InitStruct.ToggleOutState = DISABLE;
-
- GTIM_TimeBaseInit(CW_GTIM1, >IM_InitStruct);
- GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL3, GTIM_OC_OUTPUT_PWM_HIGH);
- GTIM_SetCompare3(CW_GTIM1, 0);
- GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL4, GTIM_OC_OUTPUT_PWM_HIGH);
- GTIM_SetCompare4(CW_GTIM1, 0);
- // GTIM_ITConfig(CW_GTIM1, GTIM_IT_OV, ENABLE);
- // GTIM_Cmd(CW_GTIM1, ENABLE);
-
- }
复制代码
配置时先不开启定时器及对应IO模式,主要是设置的模式前三种都是IO操作,是普通GPIO功能,而呼吸灯需要配置成复用功能。
定义一个LED的结构体:
- typedef struct
- {
- uint8_t Mode_Dis; //LED显示模式
- uint8_t Mode_OidDis; //LED上一次显示模式
- uint8_t Mode_VIE; //LED控制模式
- uint8_t state; //LED过程
- uint8_t UpFlag; //更新标志
- uint8_t Upcnt; //更新计时计数
- }LED_states;
复制代码
然后通过中断处理函数对参数进行更改,在while中循环检测LED参数,对LED的实际状态进行操作:
外部中断处理(模式切换):
- if (CW_GPIOA->ISR_f.PIN1)
- {
- GPIOA_INTFLAG_CLR(bv1);
- LED.Mode_Dis++;
- LED.Mode_Dis %= 4;
- }
复制代码
定时中断处理:
- if (GTIM_GetITStatus(CW_GTIM2, GTIM_IT_OV))
- {
- GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_OV);
- if(LED.UpFlag == 0)
- {
- if(LED.Mode_Dis == 0 || LED.Mode_Dis == 1)
- {
- LED.Upcnt++;
- if(LED.Upcnt%100 == 0)
- {
- LED.Upcnt = 0;
- LED.UpFlag = 1;
- }
- }
- else if(LED.Mode_Dis == 2)
- {
- LED.Upcnt++;
- if(LED.Upcnt%100 == 0)
- {
- LED.Upcnt = 0;
- LED.UpFlag = 1;
- LED.state++;
- LED.state %= 3;
- }
- }
- else if(LED.Mode_Dis == 3)
- {
- LED.UpFlag = 1;
- if(LED.state == 0 && LED.Upcnt < 100)
- {
- LED.Upcnt++;
- }
- if(LED.state == 0 && LED.Upcnt == 100)
- {
- LED.Upcnt--;
- LED.state = 1;
- }
- if(LED.state == 1 && LED.Upcnt > 0)
- {
- LED.Upcnt--;
- }
- if(LED.state == 1 && LED.Upcnt == 0)
- {
- LED.Upcnt++;
- LED.state = 0;
- }
- }
- }
- }
复制代码
while中循环检测代码:
- //******************************************************************************
- // 函数名称 : App_LED *
- // 函数描述 : LED模式操作 *
- // 输入参数 : *
- // 参数描述 : 无 *
- // 输出参数 : 无 *
- // 返回值 : 无 *
- //******************************************************************************
- void App_LED(void)
- {
- if(LED.Mode_OidDis != LED.Mode_Dis)
- {
- LED1Off;
- LED2Off;
- LED.Upcnt = 0;
- LED.state = 0;
- LED.UpFlag = 1;
-
- if(LED.Mode_OidDis == 3)
- {
- GTIM_Cmd(CW_GTIM1, DISABLE);
- PB08_AFx_GPIO();
- PB09_AFx_GPIO();
-
- }
-
- switch(LED.Mode_Dis)
- {
- case 0:
- LED1On;
- LED2On;
- break;
-
- case 1:
- LED1On;
- break;
-
- case 3:
- PB08_AFx_GTIM1CH3();
- PB09_AFx_GTIM1CH4();
- GTIM_Cmd(CW_GTIM1, ENABLE);
- break;
- default:
- break;
- }
- LED.Mode_OidDis = LED.Mode_Dis;
- }
-
- if(LED.UpFlag == 1)
- {
- if(LED.Mode_Dis == 0 || LED.Mode_Dis == 1)
- {
- LED1Toggle;
- LED2Toggle;
- }
- else if(LED.Mode_Dis == 2)
- {
- switch(LED.state)
- {
- case 0:
- LED1On;
- break;
-
- case 1:
- LED1Off;
- LED2On;
- break;
-
- case 2:
- LED1Off;
- LED2Off;
- break;
-
- default:
- break;
- }
- }
- else if(LED.Mode_Dis == 3)
- {
- GTIM_SetCompare3(CW_GTIM1, 50*LED.Upcnt);
- GTIM_SetCompare4(CW_GTIM1, 50*(100-LED.Upcnt));//注意根据PWM频率修改系数
- }
-
- LED.UpFlag = 0;
- }
- }
复制代码
多种多样LED功能展示就完成了!
|