从今天开始就进入例程的讲解过程,今天讲解GPIO部分,对应《AN220-CMT2380F32用户指南(微控制器部分)-CN-V1.0-20200107.pdf》7 端口控制器(GPIO)章节。
例程位置在\example\gpio文件夹中,有4个例程,下面一一进行讲解。
gpio_output例程
这个例程是输出例程,该例程功能是在按键1按下后,led灯进行闪烁。下面说一下主要代码。
- #define SK_SW1_INIT() Gpio_InitIOExt(0, 2, GpioDirIn, TRUE, FALSE, FALSE, TRUE)
- #define SK_SW1_GET() Gpio_GetIO(0, 2)
这两个宏定义是对按键1的函数,INIT是将按键1,P02配置为输入,上拉模式。GET是获取P02的IO值。根据我的开发板电路,当按键按下时IO口被拉低,get值为0,当没被按下时,由于配置为上拉电阻,所以get值为非0。
- const stc_gpio_list_t gGpiolist[] = {
- {2, 3}, // red
- {1, 4}, // green
- {1, 5}, // blue
- };
这个是LED的IO管脚配置,因为我们开发板有3个LED,所以这里数组为3个。
- SK_SW1_INIT();
- delay1ms(10);
- while (TRUE == SK_SW1_GET())
- ;
-
- //初始化外部GPIO
- for (i = 0; i < ARRAY_SZ(gGpiolist); i++) {
- Gpio_InitIOExt(gGpiolist[i].u8Port, gGpiolist[i].u8Pin, GpioDirOut, TRUE, FALSE, FALSE, FALSE);
- }
-
- //设置GPIO值(翻转)
- while (1) {
- for (i = 0; i < ARRAY_SZ(gGpiolist); i++) {
- Gpio_SetIO(gGpiolist[i].u8Port, gGpiolist[i].u8Pin, u8val);
- }
-
- u8val = !u8val;
- delay1ms(1000);
- }
以上是main函数中的主要代码,首先初始化P02,然后通过get等待按键按下。
按键按下后初始化LED为上拉输出。然后就进入while循环使用Gpio_SetIO进行IO 翻转。
gpio_input例程
- //检测K1,如果有输入为低电平,则Led1_red输出3秒
- while (1) {
- for (i = 0; i < ARRAY_SZ(gGpiolist); i++)
-
- {
- u8val = Gpio_GetIO(gGpiolist[i].u8Port, gGpiolist[i].u8Pin);
-
- if (FALSE == u8val) {
- Gpio_SetIO(gLed1list[0].u8Port, gLed1list[0].u8Pin, TRUE);
- delay1ms(3000);
- Gpio_SetIO(gLed1list[0].u8Port, gLed1list[0].u8Pin, FALSE);
- }
- }
- }
初始化流程和之前的大同小异,只是在while循环中进行了按键检测,有按键按下就把LED1点亮3秒。
gpio_irq例程
该例程是展示IO的中断功能。上电时led2,led3电量,按键1按下后led2会熄灭3秒,然后点亮。
- //将中断触发功能
- for (i = 0; i < ARRAY_SZ(gIrqList); i++) {
- Gpio_EnableIrq(gIrqList[i].u8Port, gIrqList[i].u8Pin, GpioIrqFalling);
- }
-
- //开启GPIO总中断
- EnableNvic(PORT0_IRQn, DDL_IRQ_LEVEL_DEFAULT, TRUE);
-
- while (1)
- ;
主函数中将P02配置为下降沿触发,GpioIrqFalling。EnableNvic使能中断。
- void Gpio_IRQHandler(uint8_t u8Param)
- {
- SK_LED_SET(1);
- delay1ms(3000);
- SK_LED_SET(0);
- delay1ms(2000);
-
- *((uint32_t *)((uint32_t)&M0P_GPIO->P0ICLR + u8Param * 0x40)) = 0;
- }
在中断函数中将led2关闭3秒后打开,整个中断占用5秒时间,整个只是示例,真正代码中要尽量减小中断中的时间。
gpio_lpm例程
该例程功能是通过配置IO 中断,将睡眠的模块唤醒。上电后,按下按键1,LED2,LED3点亮,然后LED2熄灭2秒,然后在过2秒后模块进入睡眠,这时如果再按下按键1,LED2会熄灭2秒,然后再亮起。下面看一下逻辑。
- //将中断触发功能
- for (i = 0; i < ARRAY_SZ(gIrqList); i++) {
- Gpio_EnableIrq(gIrqList[i].u8Port, gIrqList[i].u8Pin, GpioIrqFalling);
- }
-
- EnableNvic(PORT0_IRQn, DDL_IRQ_LEVEL_DEFAULT, TRUE);
-
- M0P_GPIO->CTRL0_f.IESEL = 1;
-
- Clk_SetFunc(ClkFuncWkupRCH, TRUE);
- SCB->SCR |= 0x4; // sleepdeep
- __NOP();
- __NOP();
- __NOP();
- __NOP();
- __NOP();
-
- while (1) {
- SK_LED_SET(1);
- delay1ms(2000);
- SK_LED_SET(0);
- delay1ms(2000);
- __WFI(); // goto LPM Mode
- }
设置中断,然后点亮LED2,LED3。然后在while中先熄灭LED2两秒后在点亮,两秒后在进入睡眠,等待IO中断唤醒,继续进行while逻辑。
这次的中断处理中只是清除了中断标志位。
void Gpio_IRQHandler(uint8_t u8Param) { *((uint32_t *)((uint32_t)&M0P_GPIO->P0ICLR + u8Param * 0x40)) = 0; }
这个函数初始化的等待按键1按下的逻辑是必须的,因为模块进入睡眠后就无法链接调试器进行下载了。
- // SW1 控制程序继续运行
- //注:此处如程序继续运行,因演示需要会将SWD及RESET配置为IO功能,如使用该Demo请勿删除如下两行代码。
- SK_SW1_INIT();
- NextStep();
GPIO就是这些,也是比较简单的例程,没有太多东西,提供的库都有很详细的汉语注释,参数什么的都可以很容易的理解用途,对开发很友好。