- #include "gpio.h"
- void led_init(void)
- {
- stc_gpio_cfg_t stcGpioCfg;
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
- stcGpioCfg.enDir = GpioDirOut;
- stcGpioCfg.enPu = GpioPuDisable;
- stcGpioCfg.enPd = GpioPdEnable;
- Gpio_ClrIO(STK_LED_PORT, STK_LED_PIN);
- Gpio_Init(STK_LED_PORT, STK_LED_PIN, &stcGpioCfg);
- }
- void key_init(void)
- {
- stc_gpio_cfg_t stcGpioCfg;
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
- stcGpioCfg.enDir = GpioDirIn;
- stcGpioCfg.enPu = GpioPuDisable;
- stcGpioCfg.enPd = GpioPdDisable;
- Gpio_Init(STK_USER_PORT, STK_USER_PIN, &stcGpioCfg);
- }
- int32_t main(void)
- {
- led_init();
- key_init();
- while(1)
- {
- if(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE)
- {
- delay1ms(10);
- while(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE);
- Gpio_WriteOutputIO(STK_LED_PORT, STK_LED_PIN,!Gpio_ReadOutputIO(STK_LED_PORT, STK_LED_PIN));
- }
- }
- }
编译烧录查看效果
3.2按键中断方式
与上面的轮询方法不同,这种方式并不用一直查询GPIO的状态,按键状态改变时会产生中断,程序在检测到中断后再判断按键状态
查看interrupts_hc32l19x.c这个文件,这是官方提供的一个统一中断入口文件
可以看到在GPIOA的中断函数里调用了PortA_IRQHandler这个方法,这个方法面用了__WEAK声明
按照interrupts_hc32l19x.h的注释说明,可以在需要的地方重新定义这个方法
使用这种方式要把这里填上
代码示例
- #include "gpio.h"
- void led_init(void)
- {
- stc_gpio_cfg_t stcGpioCfg;
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
- stcGpioCfg.enDir = GpioDirOut;
- stcGpioCfg.enPu = GpioPuDisable;
- stcGpioCfg.enPd = GpioPdEnable;
- Gpio_ClrIO(STK_LED_PORT, STK_LED_PIN);
- Gpio_Init(STK_LED_PORT, STK_LED_PIN, &stcGpioCfg);
- }
- void key_init(void)
- {
- stc_gpio_cfg_t stcGpioCfg;
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
- stcGpioCfg.enDir = GpioDirIn;
- stcGpioCfg.enDrv = GpioDrvL;
- stcGpioCfg.enPu = GpioPuDisable;
- stcGpioCfg.enPd = GpioPdDisable;
- Gpio_Init(STK_USER_PORT, STK_USER_PIN, &stcGpioCfg);
- Gpio_EnableIrq(STK_USER_PORT, STK_USER_PIN, GpioIrqFalling);
- EnableNvic(PORTA_IRQn, IrqLevel3, TRUE);
- }
- void PortA_IRQHandler(void)
- {
- if(TRUE == Gpio_GetIrqStatus(STK_USER_PORT, STK_USER_PIN))
- {
- if(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE)
- {
- Gpio_WriteOutputIO(STK_LED_PORT, STK_LED_PIN,!Gpio_ReadOutputIO(STK_LED_PORT, STK_LED_PIN));
- }
- Gpio_ClearIrq(STK_USER_PORT, STK_USER_PIN);
- }
- }
- int32_t main(void)
- {
- led_init();
- key_init();
- while(1)
- {
- ;
- }
- }
运行效果
3.3定时器测试
HC32L196有4个通用定时器、2个低功耗定时器和3个高级定时器,还有一个PCA(可编程计数器阵列)也可作为定时器使用
选用Timer0做一个每1ms触发一次的定时器,用它来控制LED闪烁,按键调节闪烁速度
首先设置一下系统时钟,不做任何更改时用的是内部时4M时钟
板子上有个32M的外部晶振,接下来使用它作为时钟源
- void xth_init()
- {
- //当使用的时钟源HCLK大于24M:设置FLASH 读等待周期为1 cycle
- Flash_WaitCycle(FlashWaitCycle1);
- Sysctrl_SetXTHFreq(SysctrlXthFreq24_32MHz);
- Sysctrl_XTHDriverCfg(SysctrlXtalDriver3);
- Sysctrl_SetXTHStableTime(SysctrlXthStableCycle16384);
- Sysctrl_ClkSourceEnable(SysctrlClkXTH, TRUE);
- delay1ms(10);
- Sysctrl_SysClkSwitch(SysctrlClkXTH);
- }
设置timer0参数,使用16位重载计数器模式,计数器会从设定的值开始计数到0xFFFF后产生中断
- void timer0_init()
- {
- stc_bt_mode0_cfg_t stcBtBaseCfg;
- DDL_ZERO_STRUCT(stcBtBaseCfg);
- Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE); //Base Timer外设时钟使能
-
- stcBtBaseCfg.enWorkMode = BtWorkMode0; //定时器模式
- stcBtBaseCfg.enCT = BtTimer; //定时器功能,计数时钟为内部PCLK
- stcBtBaseCfg.enPRS = BtPCLKDiv32; //PCLK/32 32M/32=1M
- stcBtBaseCfg.enCntMode = Bt16bitArrMode; //自动重载16位计数器/定时器
- stcBtBaseCfg.bEnTog = FALSE;
- stcBtBaseCfg.bEnGate = FALSE;
- Bt_Mode0_Init(TIM0, &stcBtBaseCfg); //TIM0 的模式0功能初始化
-
- Bt_M0_ARRSet(TIM0, 0x10000-1000); //设置重载值
- Bt_M0_Cnt16Set(TIM0, 0x10000-1000); //设置计数初值
-
- Bt_ClearIntFlag(TIM0,BtUevIrq); //清中断标志
- Bt_Mode0_EnableIrq(TIM0); //使能TIM0中断
- EnableNvic(TIM0_IRQn, IrqLevel3, TRUE); //TIM0中断使能
- Bt_M0_Run(TIM0); //TIM0 运行。
- }
中断处理
- uint16_t timecount = 0;
- uint16_t timecount_max = 500;
- void Tim0_IRQHandler(void)
- {
- //Timer0 模式0 溢出中断
- if(TRUE == Bt_GetIntFlag(TIM0, BtUevIrq))
- {
- if(timecount < timecount_max)
- timecount += 1;
- else
- {
- timecount = 0;
- Gpio_WriteOutputIO(STK_LED_PORT, STK_LED_PIN,!Gpio_ReadOutputIO(STK_LED_PORT, STK_LED_PIN));
- }
- Bt_ClearIntFlag(TIM0,BtUevIrq); //中断标志清零
- }
- }
- void PortA_IRQHandler(void)
- {
- if(TRUE == Gpio_GetIrqStatus(STK_USER_PORT, STK_USER_PIN))
- {
- if(Gpio_GetInputIO(STK_USER_PORT, STK_USER_PIN) == FALSE)
- {
- if(timecount_max == 500)
- timecount_max = 200;
- else if(timecount_max == 200)
- timecount_max = 1000;
- else
- timecount_max = 500;
- }
- Gpio_ClearIrq(STK_USER_PORT, STK_USER_PIN);
- }
- }
main函数
- int32_t main(void)
- {
- xth_init();
- //时钟分频设置
- Sysctrl_SetHCLKDiv(SysctrlHclkDiv1);
- Sysctrl_SetPCLKDiv(SysctrlPclkDiv1);
- led_init();
- key_init();
- timer0_init();
- while(1)
- {
- ;
- }
- }
运行效果
3.4PWM输出测试
4个通用定时器3个高级定时器和PCA都有输出PWM的能力,然而开发板上LED所接的PD14这个IO并不能输出PWM
因此外接2个LED来测试PWM,选用PA00和PA01作为Timer1的两个PWM通道输出
初始化为PWM输出
- void pwm_led_init()
- {
- stc_gpio_cfg_t stcLEDPort;
- DDL_ZERO_STRUCT(stcLEDPort);
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
- stcLEDPort.enDir = GpioDirOut;
- Gpio_Init(GpioPortA, GpioPin0, &stcLEDPort);
- Gpio_SetAfMode(GpioPortA,GpioPin0,GpioAf5); //PA00设置为TIM1_CHA
-
- Gpio_Init(GpioPortA, GpioPin1, &stcLEDPort);
- Gpio_SetAfMode(GpioPortA,GpioPin1,GpioAf5); //PA01设置为TIM1_CHB
- }
接下来看看手册上对于定时器PWM模式的描述
这里选用PWM2上计数,锯齿波单点比较,时钟32分频计数周期1000
- void pwm_timer1_init()
- {
- stc_bt_mode23_cfg_t stcBtBaseCfg;
- stc_bt_m23_compare_cfg_t stcBtPortCmpCfg;
- DDL_ZERO_STRUCT(stcBtBaseCfg);
- DDL_ZERO_STRUCT(stcBtPortCmpCfg);
- Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE);
- stcBtBaseCfg.enWorkMode = BtWorkMode2; //锯齿波模式
- stcBtBaseCfg.enCT = BtTimer; //定时器功能,计数时钟为内部PCLK
- stcBtBaseCfg.enPRS = BtPCLKDiv32; //PCLK
- stcBtBaseCfg.enCntDir = BtCntUp; //向上计数,在三角波模式时只读
- stcBtBaseCfg.enPWMTypeSel = BtIndependentPWM; //独立输出PWM
- stcBtBaseCfg.enPWM2sSel = BtSinglePointCmp; //单点比较功能
- stcBtBaseCfg.bOneShot = FALSE; //循环计数
- stcBtBaseCfg.bURSSel = FALSE; //上下溢更新
- Bt_Mode23_Init(TIM1, &stcBtBaseCfg); //TIM0 的模式23功能初始化
-
- Bt_M23_ARRSet(TIM1, 1000-1, TRUE); //设置重载值,并使能缓存
- Bt_M23_CCR_Set(TIM1, BtCCR0A, 0); //设置比较值A
- Bt_M23_CCR_Set(TIM1, BtCCR0B, 0); //设置比较值B
-
- stcBtPortCmpCfg.enCH0ACmpCtrl = BtPWMMode2; //OCREFA输出控制OCMA:PWM模式2
- stcBtPortCmpCfg.enCH0APolarity = BtPortPositive; //正常输出
- stcBtPortCmpCfg.bCh0ACmpBufEn = TRUE; //A通道缓存控制
- stcBtPortCmpCfg.enCh0ACmpIntSel = BtCmpIntNone; //A通道比较控制:无
-
- stcBtPortCmpCfg.enCH0BCmpCtrl = BtPWMMode2; //OCREFB输出控制OCMB:PWM模式2
- stcBtPortCmpCfg.enCH0BPolarity = BtPortPositive; //正常输出
- stcBtPortCmpCfg.bCH0BCmpBufEn = TRUE; //B通道缓存控制使能
- stcBtPortCmpCfg.enCH0BCmpIntSel = BtCmpIntNone; //B通道比较控制:无
-
- Bt_M23_PortOutput_Cfg(TIM1, &stcBtPortCmpCfg); //比较输出端口配置
- //事件更新周期设置,0表示锯齿波每个周期更新一次,每+1代表延迟1个周期
- Bt_M23_SetValidPeriod(TIM1,0); //间隔周期设置
- Bt_M23_Cnt16Set(TIM1, 0); //设置计数初值
- Bt_M23_EnPWM_Output(TIM1, TRUE, FALSE); //TIM0 端口输出使能
- Bt_M23_Run(TIM1);
- }
两个LED交替呼吸
- int32_t main(void)
- {
- uint16_t pwm = 0;
- xth_init();
- //时钟分频设置
- Sysctrl_SetHCLKDiv(SysctrlHclkDiv1);
- Sysctrl_SetPCLKDiv(SysctrlPclkDiv1);
- led_init();
- key_init();
- timer0_init();
- pwm_led_init();
- pwm_timer1_init();
- while(1)
- {
- if(pwm<2000)
- pwm += 1;
- else
- pwm = 0;
- if(pwm < 1000)
- {
- Bt_M23_CCR_Set(TIM1, BtCCR0A, pwm);
- Bt_M23_CCR_Set(TIM1, BtCCR0B, 1000-pwm);
- }
- else
- {
- Bt_M23_CCR_Set(TIM1, BtCCR0A, 2000 - pwm);
- Bt_M23_CCR_Set(TIM1, BtCCR0B, pwm - 1000);
- }
- delay1ms(2);
- }
- }
运行效果