本帖最后由 秦生0303 于 2022-7-10 20:00 编辑
#申请原创#
在上一贴,很多人留言说点灯被玩坏了,感觉大家对此都不满足,这里还是要再强调一下,那不是点灯,只是一个时钟配置后的一个验证,本人习惯通过操作IO口来验证一下程序正常运行,LED比较直观而已,在最开始是非常发生一些意想不到的错误的。
言归正传,点灯在各位大神的手里已经已经玩出花样了,芯源的测试板板载可控的LED只有两个,想想都可以做什么呢?循环灯、同亮同灭、循环闪烁、再加上一个高级点的呼吸灯。
接下来重点分析一下实现这些功能够需要什么?
循环灯、同亮同灭、循环闪烁基本操作就是IO口的翻转,不过期间需要延时功能,一种是原地等待,一种是定时器定时,这里选择定时器定时,相对来说定时器定时精准;
呼吸灯涉及到的就是定时器的PWM输出了,查阅数据手册发现:
PB8/9可以连接通用定时器(GTIM) ,可以产生输出波形(输出比较和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;
- }
定时中断处理:
|