入门一款单片机,一般从单片机输出0/1开始,最直观的现象现象就是点亮一个LED、让一个LED亮灭闪烁、多个LED流水灯等
GD32L233C-START板载4颗LED,因此,就着这4颗LED,也是可以有很多玩法的。
一、已有资源分析
官方提供了丰富的资源,主要有GD32L23x_Firmware_Library_V1.0.1,GD32L23x_AddOn_V1.0.0(GigaDevice.GD32L23x_DFP_1.0.0.pack)和GD32L23x_Demo_Suites_V1.1.0。
通过分析以上资源的源码,GD32L23x_Firmware_Library_V1.0.1是最新的标准库版本,基于V1.0.0,部分外设有所修改。同时提供了基于GD32L233R-EVAL-V1.0 board的丰富例程。
GD32L23x_AddOn_V1.0.0提供了KEIL和IAR的pack包。安装后KEIL中显示版本是V0.0.0,但通过打开库文件源码,可以看到应该和GD32L23x_Firmware_Library_V1.0.1是同步的。
GD32L23x_Demo_Suites_V1.1.0主要提供了GD32L233C-START、GD32L233K_START\GD32L233R_EVAL三块板子的例程。因为START作为入门板子的原因,板载资源有限,例程仅有LED、Key、EXTI_Key、USART、TIMER_Key、USBD_CDC的例程。
另外三个资源包虽然标准库版本一样,但是查看文件大小,部分源代码文件大小有差异。这个需要在使用的时候注意一下。
二、 GD32L233C-START LED硬件电路
GD32L233C-START的LED总共有4个,分别有PA7、PA8、PC6、PC7四个引脚控制,高电平有效。
三、GD32L23x_Demo_Suites_V1.1.0 中的点灯程序
将GD32L23x_Demo_Suites_V1.1.0 压缩包解压到非中文目录,然后打开第一个例程,编译,0error,0warning。然后确认一下工程的option选项信息,使用CMSIS-DAP。
下载后,可以看到4颗LED,依次点亮。
四、源码分析
4.1 systick配置及使用
4.1.1 配置
void systick_config(void)
{
/* setup systick timer for 1000Hz interrupts */
if(SysTick_Config(SystemCoreClock / 1000U)) {
/* capture error */
while(1) {
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
配置程序比较简单,调用两个库函数,SysTick_Config()根据系统时钟和定时周期来进行systick的时钟配置和工作模式的配置。SysTick_Config()配置systick的中断优先级。
4.1.2 使用
volatile static uint32_t delay;
void delay_decrement(void)
{
if(0U != delay) {
delay--;
}
}
void delay_1ms(uint32_t count)
{
delay = count;
while(0U != delay) {
}
}
首先,定义一个用于tick中断中进行减操作的变量。然后delay_decrement()函数在tick中断中被调用,当delay不为0,减一。使用delay_1ms()在需要ms级延时的地方进行延时,参数为要延时的毫秒数。
***这样的延时函数,其实是有局限性的。比如在调用一次delay_1ms(10)之后,经过10ms延时,在下一次调用delay_1ms()之前,delay是一直为0的。相较于STM32中一直使用的systick的延时方式,GD给的tick延时函数有非常大的局限性。也就只能作为延时函数使用了。
4.2 GPIO配置及置位/清零操作
/* enable the LED GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* configure LED GPIO pin */
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7 | GPIO_PIN_8);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7 | GPIO_PIN_8);
/* reset LED GPIO pin */
gpio_bit_reset(GPIOA, GPIO_PIN_7 | GPIO_PIN_8);
/* set LED GPIO pin */
gpio_bit_set(GPIOA, GPIO_PIN_7 | GPIO_PIN_8);
三部曲:第一步:开时钟;第二步:gpio_mode_set()设置输入输出、上下拉,gpio_output_options_set()设置输出类型、速度;第三步:gpio_bit_reset()、gpio_bit_set()函数进行引脚输出置位/清零操作。 每一个函数,操作的引脚都可以其中任意多个,并且可以是非连续引脚。
/* set GPIO pin bit */
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin);
/* reset GPIO pin bit */
void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin);
/* write data to the specified GPIO pin */
void gpio_bit_write(uint32_t gpio_periph, uint32_t pin, bit_status bit_value);
/* write data to the specified GPIO port */
void gpio_port_write(uint32_t gpio_periph, uint16_t data);
/* get GPIO pin input status */
FlagStatus gpio_input_bit_get(uint32_t gpio_periph, uint32_t pin);
/* get GPIO port input status */
uint16_t gpio_input_port_get(uint32_t gpio_periph);
/* get GPIO pin output status */
FlagStatus gpio_output_bit_get(uint32_t gpio_periph, uint32_t pin);
/* get GPIO port output status */
uint16_t gpio_output_port_get(uint32_t gpio_periph);
/* set GPIO alternate function */
void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin);
/* lock GPIO pin bit */
void gpio_pin_lock(uint32_t gpio_periph, uint32_t pin);
/* toggle GPIO pin status */
void gpio_bit_toggle(uint32_t gpio_periph, uint32_t pin);
/* toggle GPIO port status */
void gpio_port_toggle(uint32_t gpio_periph);
库文件中,对于GPIO的操作,无论是输入还是输出,基本上涵盖了日常用到的所有操作。使用的时候直接调用对应的函数就行。
流水灯改造:
将下边的代码做以下修改
/* reset LED GPIO pin 修改前*/
gpio_bit_reset(GPIOA, GPIO_PIN_7 | GPIO_PIN_8);
gpio_bit_reset(GPIOC, GPIO_PIN_6 | GPIO_PIN_7);
/* reset LED GPIO pin 修改后*/
gpio_bit_reset(GPIOA, GPIO_PIN_7 | GPIO_PIN_8);
gpio_bit_set(GPIOC, GPIO_PIN_6 | GPIO_PIN_7);
然后将while(1)中的内容做如下改动(将原来的代码注释掉,增加下边的三行):
/* turn on LED1, turn off LED4 */
// gpio_bit_set(GPIOA, GPIO_PIN_7);
// gpio_bit_reset(GPIOC, GPIO_PIN_7);
// delay_1ms(500);
// /* turn on LED2, turn off LED1 */
// gpio_bit_set(GPIOA, GPIO_PIN_8);
// gpio_bit_reset(GPIOA, GPIO_PIN_7);
// delay_1ms(500);
// /* turn on LED3, turn off LED2 */
// gpio_bit_set(GPIOC, GPIO_PIN_6);
// gpio_bit_reset(GPIOA, GPIO_PIN_8);
// delay_1ms(500);
// /* turn on LED4, turn off LED3 */
// gpio_bit_set(GPIOC, GPIO_PIN_7);
// gpio_bit_reset(GPIOC, GPIO_PIN_6);
// delay_1ms(500);
gpio_bit_toggle(GPIOA, GPIO_PIN_7 | GPIO_PIN_8);
gpio_bit_toggle(GPIOC, GPIO_PIN_6 | GPIO_PIN_7);
delay_1ms(500);
一个新的流水灯就有了。有了标准库,点灯是不是很简单。
本帖最后由 wo4fisher 于 2022-1-16 14:52 编辑引用: Jacktang 发表于 2022-1-16 21:09 有了标准库,点灯确实很简单。
其实,主要还是底层决定的。arm框架下,用了一款芯片,很容易迁移到别的厂家同样内核的芯片上。
ST在手册和标准库(当然不只是标准库)以及芯片配置代码(cubemx)自动化上,国产大厂好像追的不是很给力,反而一些小厂做的还好一些。