这节内容主要是介绍UCM108E的片内外设使用情况,同样也是用官方提供的二次开发demo来做进一步的开发。
UC8188的GPIO使用起来比较简单,官方也提供了比较全面的函数库。GPIO控制器可以驱动或者获取信号/数据。通过相应的寄存器,可以定义I/O的功能、方向、状态以及中断。
- 受控I/O个数微29
- I/O输入/输出可配
- 输入/输出状态:上拉、浮空
- 所有I/O均可作为中断源,触发方式可配:低电平、高电平、上升沿、下降沿
- I/O功能多重复用
同时也需要指出,GPIO的功能并没有类似于STM32类型的MCU多,比如IO都不支持下拉功能,所以在进行硬件设计的时候,需要详细参考GPIO特性,在硬件设计上面不足或者规避这些不足。
操作GPIO为外部中断触发模式,主要是由以下几个步骤:
static void trigger_gpio_init(void)
{
gpio_set_pin_direction(UC_GPIO, TRIGGER_GPS_PPS_GPIO, GPIO_DIR_IN);
gpio_set_irq_type(UC_GPIO, TRIGGER_GPS_PPS_GPIO, GPIO_IT_RISE_EDGE);
gpio_set_irq_en(UC_GPIO, TRIGGER_GPS_PPS_GPIO, 1);
gpio_int_enable();//enable gpio interrupt
printf("trigger gpio pin init done.\r\n");
}
/*
* [url=home.php?mod=space&uid=2666770]@Brief[/url] GPIO interrupt service function
* [url=home.php?mod=space&uid=3142012]@param[/url] None
* @retval None
*/
void gpio_handler(void)
{
uint32_t pin, status;
status = gpio_get_irq_status(UC_GPIO); // get gpip irq status
gpio_int_clear_pending(); // clear gpio interrupt pending
for (pin = GPIO_PIN_0; pin <= GPIO_PIN_29; pin++) {
if (status & (1 << pin)) {
printf("GPIO %d INTERRPUT\r\n", pin);
}
}
}
注意:
- 中断标记位一定要在中断服务函数里面清除,不然下次无法继续触发中断
- 中断服务函数的入口是
gpio_handler
,在UC8188的单独示例中,中断服务函数是ISR_GPIO
- 在本示例工程的
libraries/HAL_Drivers/drv_gpio.c
中也有gpio_handler
需要将此先屏蔽,然后自己实现这个中断服务函数
将上述代码编译完成后,烧录到开发板运行,然后手动触发GPIO25,可以看到中断打印
Time: 2022/6/18 19:53:38.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
Time: 2022/6/18 19:53:39.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
Time: 2022/6/18 19:53:40.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
Time: 2022/6/18 19:53:41.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
GPIO 25 INTERRPUT
Time: 2022/6/18 19:53:42.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
GPIO 25 INTERRPUT
Time: 2022/6/18 19:53:43.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
GPIO 25 INTERRPUT
Time: 2022/6/18 19:53:44.00
POS: ST 10, tLon 1.899968, tLat 0.596802, fAlt: 38.554977
GPIO 25 INTERRPUT
UC8188有两个独立的定时器,设计的也比较简单。
我主要是用定时器来做一个精确计时,所以只用了定时中断功能。在确定定时时间之前,需要确定系统主频,分频系数等关键指标。通过研读代码我们可知在启动函数那里,配置了系统主频
addi x11, x0, 70 //131.072Mhz-->0xc80000, 115200 for sim
jal uart_set_cfg
cfg.pre = 7;
cfg.cnt = 0xffffffffU - ((SYSTEM_CLK>>8)/(cfg.pre+1))*1;// 1/256 S
cfg.cmp = 0;//It must be 0 in this mode.
timer_init(UC_TIMER1, &cfg);
timer_enable(UC_TIMER1);
timer_int_enable(UC_TIMER1, TIMER_IT_OVF);
int_enable();
static int cnt = 0;
timer_int_clear_pending(UC_TIMER1, TIMER_IT_OVF);
// 这里和上面的初始化是一样的,简化了一下算法
timer_set_count(UC_TIMER1, 0xffffffffU - (SYSTEM_CLK>>11));//1S]
cnt++;
if(cnt%0xff == 0){
printf("timer1 overflow interrupt!!!\r\n");
}
编译上述代码,在串口工具中应该会每隔1s打印一下
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
timer1 overflow interrupt!!!
PWM外设相对来说也是比较简单。
我的需求是,可以调节一个灯的亮度,并且可以周期的控制灯的闪烁逻辑。
pwm_enable(UC_PWM3);
pwm_set_period(UC_PWM3, 1000);
pwm_set_duty(UC_PWM3, 300);
while(1)
{
printf("cnt : %d\r\n", cnt++);
pwm_set_duty(UC_PWM3, 30); // led on light:3%
delay_ms(500);
pwm_set_duty(UC_PWM3, 0); // led off
delay_ms(500);
}
注意:这里我尝试使用
pwm_enable
和pwm_disable
来控制灯的亮灭,但是发现pwm_disable
后GPIO默认是高电平,不符合我的设计需求,故用占空比为0表示灯灭,由于PWM外设过于简单,在做硬件设计的时候需要注意这里。
将上述代码烧录到开发板,可以看到1s一次打印cnt值,同时LED灯也在闪烁,改变duty可以改变led亮度
pwm test
cnt : 0
cnt : 1
cnt : 2
cnt : 3
cnt : 4
cnt : 5
UC8188的外设使用起来很简单,也很实用。但是在做相关硬件设计时,需要注意。
更多回帖