先抛开本次的开发板不谈,聊一聊课程1所要实现的目标:点亮RGB,实现红色、绿色、蓝色的循环显示。大家可能都实现过点灯,这也是我们在拿到开发板后首先实现的目标,或者出厂开发板板载的程序一般也是这个,本次课程1课后作业所实现的目标实际上可以说是对于点灯的升级版,数量升级到三个(红绿蓝),进行循环显示需要首先实现对上一个LED灯的关闭,然后在打开下一个LED的显示。
课程1中我们学习了普通IO口的输出控制,输入按键采集的实践,以及PWM控制方法。通过课程的学习设计本次作业的实现。该开发板就板载了1 个 RGB LED,所以我们可以仅仅通过这个开发板就可以实现课程1的实现,仅仅通过要求的字面意思将功能进行一下分解,点亮RGB实际上就是IO口的操作,循环显示涉及的方面主要是循环顺序、间隔、以及实现方法的问题,这里我们先暂定顺序为红——绿——蓝,间隔为500ms(太短可能无法分辨出来,最好不要小于200ms,太大的等待时间太长),实现方式这里准备通过两种方法实现(阻塞式与非阻塞式),也可以说是延时转换或者定时器转化。再结合所学内容加入按键的操作以及呼吸灯进行状态展示(按键按下后呼吸灯开始,同时RGB三色循环)。
我们先看一下开发板中有关LED的原理图:
有关按键的原理图:
硬件部分还是很简单的,RGB是共地的,所以高电平可以实现对应LED的点亮。
接下来就是软件部分的实现,在这里我们需要先安装一下开发环境,涉及的部分主要是CCS这个软件,还是有就是MSPM0 SDK。https://www.ti.com.cn/product/cn/MSPM0L1306这是TI有关本开发板的所有资料,你们可以在这里找到上述必备的信息与软件,下载资源也非常的流畅。建议还是使用官方推荐的开发环境,毕竟是新出来的芯片,很多开发环境的支持可能会有意想不到的麻烦。注意MSPM0微控制器和 MSPM0 SDK 需要 CCS 12.3或更高版本。目前最高版本是CCS 12.7.
软件启动后可以看到快速启动界面,我们创建一个属于自己的工程,选择“New Project”;
一定要选择SDK,只有这样才能快速启动配置文件,一种类似STM32CubeMX一样神奇的东西,而且这个配置文件还是随工程的,这个可是目前我见到的唯一这种模式的,我也尝试直接创建工程,不过由于CCS这种工具链的模式,总是有各种问题,使用SDK就都帮你配置好了,你只需要实现你的代码就可以了。
使用SDK创建的也是一个空的工程,我们可以自由发挥,进去会看到REDME,这个工程有关调试相关的引脚都已经配置好且进行了介绍;
添加GPIO,在添加不同的三个引脚,注意蓝色区域的选择,GPIO分为上16和下16的分区,大于等于16的引脚需要选择“Upper”。
我们创建LED1的PWM控制,如上图,记得下面还有一个引脚的配置,选择PA0;
创建引脚S2的采集,本次通过中断方式进行采集:
这里有个注意事项,S2的按键没有初始状态,在按键按下的时候是接地的状态,所以在引脚配置的时候要上拉一下。
另外一种的实现需要通过定时实现,我们在配置文件里面创建一个定时器:
为了RGB三色循环显示功能在定时器中实现,原定要直接配置500ms的定时器,不过呼吸灯的作用也想在这个定时器中实现,所以就改为小数值10ms定时。
我们直接编译就可以生成初始化代码了。
按键方面的处理代码如下:
void GROUP1_IRQHandler(void) { switch (DL_GPIO_getPendingInterrupt(GPIO_KEY_PORT)) { case GPIO_KEY_S2_IIDX: if(RGB_state_OnOrOff) { RGB_state_OnOrOff = 0; DL_TimerG_setCaptureCompareValue(LED_PWM_0_INST, 1000, DL_TIMER_CC_0_INDEX); DL_TimerG_stopCounter(LED_PWM_0_INST); DL_TimerG_stopCounter(TIMER_0_INST); } else { RGB_state_OnOrOff = 1; DL_TimerG_setCaptureCompareValue(LED_PWM_0_INST, 1000, DL_TIMER_CC_0_INDEX); DL_TimerG_startCounter(LED_PWM_0_INST); LED_PWM_cnt = 0; DL_TimerG_startCounter(TIMER_0_INST); } break; default: break; } }
通过在按键中断中的处理,我们可以给予初始状态的赋予或者设置,例如PWM的初始百分比等等,不启动时相关定时或者PWM输出关闭。
定时器中呼吸灯部分实现:
LED_PWM_cnt++; if(LED_PWM_cnt >= 5 && LED_PWM_cnt <= 95) { DL_TimerG_setCaptureCompareValue(LED_PWM_0_INST, 10*(100-LED_PWM_cnt), DL_TIMER_CC_0_INDEX); } else if(LED_PWM_cnt > 105 && LED_PWM_cnt <= 195) { DL_TimerG_setCaptureCompareValue(LED_PWM_0_INST, 10*(LED_PWM_cnt-100), DL_TIMER_CC_0_INDEX); } if(LED_PWM_cnt >= 200) LED_PWM_cnt = 0;
在这里没有选择0开始是因为切换状态是会出现明显的突变,看着效果不太好。总的呼吸灯的呼吸周期是200*10ms。
接下来就实现阻塞式循环点亮:
if(RGB_state_OnOrOff == 1) { delay_cycles(32000000); DL_GPIO_clearPins(GPIO_RGB_PORT, GPIO_RGB_PIN_BIUE_PIN); DL_GPIO_setPins(GPIO_RGB_PORT, GPIO_RGB_PIN_RED_PIN); delay_cycles(32000000); DL_GPIO_clearPins(GPIO_RGB_PORT, GPIO_RGB_PIN_RED_PIN); DL_GPIO_setPins(GPIO_RGB_PORT, GPIO_RGB_PIN_GREEN_PIN); delay_cycles(32000000); DL_GPIO_clearPins(GPIO_RGB_PORT, GPIO_RGB_PIN_GREEN_PIN); DL_GPIO_setPins(GPIO_RGB_PORT, GPIO_RGB_PIN_BIUE_PIN); }
为了区分两次的实验效果,这里的阻塞式选用的循环周期为1s,这里涉及到的就是延时程序和IO口的直接操作了,注意放置的位置和循环顺序是相关的,关闭显示后的效果最终会停留在蓝色灯显示,效果如下:
非阻塞循环显示的代码主要在定时器中断中实现:
if(RGB_state_OnOrOff == 1) { Tmer_cnt++; if(Tmer_cnt%50 == 0) { state++; state %= 3; } switch(state) { case 0: DL_GPIO_clearPins(GPIO_RGB_PORT, GPIO_RGB_PIN_BIUE_PIN); DL_GPIO_setPins(GPIO_RGB_PORT, GPIO_RGB_PIN_RED_PIN); break; case 1: DL_GPIO_clearPins(GPIO_RGB_PORT, GPIO_RGB_PIN_RED_PIN); DL_GPIO_setPins(GPIO_RGB_PORT, GPIO_RGB_PIN_GREEN_PIN); break; case 2: DL_GPIO_clearPins(GPIO_RGB_PORT, GPIO_RGB_PIN_GREEN_PIN); DL_GPIO_setPins(GPIO_RGB_PORT, GPIO_RGB_PIN_BIUE_PIN); break; default: break; } }
非阻塞式的IO口操作是在中断中进行的,所以不再需要延时程序,这里需要一个变量进行状态判断,注意开启中断。效果如下:
到这里我们基本上就完成课程1的内容,我们从任务分解、硬件原理、软件实现,再到效果展示,对课程需要的内容进行一一实现,体验到了TI开发的便捷条件,非常的丝滑。