一、前言
首先了解一下板卡上自带的4个LED,
分别对应PA7、PA8、PC6、PC7控制,对于LED的控制涉及单片机最基础的IO控制,上图我们看到4个LED是共地的,故IO输出为高则点亮LED,本开发板单片机系统的供电电压为3.3V,点亮LED4后,测量的R5的电压为1.27V,故该路电流为1.27V/470R=2.7mA。
二、目标
开发板初始demo程序一般搭载的都是走马灯程序,直观简单,使用延时方法阻塞式进行LED控制,我们换一种方法通过定时器实现LED的控制,藉此可以了解熟悉单片机的IO控制和普通定时器的定时功能,由于LED资源比较充足,这里我们较多的展示LED例如最常见的走马灯,同亮同灭闪烁,间隔闪烁等。
三、代码介绍
对于IO的控制流程:
第一步:打开对应IO的时钟,例如PA引脚rcu_periph_clock_enable(RCU_GPIOA);
第二步:进行具体IO口的初始化,例如PA7引脚gpio_mode_set(GPIOA,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLDOWN,GPIO_PIN_7),gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7),对于引脚是否上拉下拉问题,个人喜欢与引脚的初始状态保持一致,对于这些LED的控制引脚的希望初始状态都为低,需要输出能力的引脚需配置为推挽输出。这里有一个问题,可能不是同一个团队的原因或者有特殊考量,GD32F303系列只用了一个函数即可进行IO口初始化,这里需要两部才能配置完成;
第三步:就是IO的高低输出配置了。
IO口初始化代码:
#define GD_RCU_GPIOA_INIT rcu_periph_clock_enable(RCU_GPIOA)
#define GD_RCU_GPIOC_INIT rcu_periph_clock_enable(RCU_GPIOC)
#define GD_LED1_On gpio_bit_set(GPIOA,GPIO_PIN_7)
#define GD_LED1_Off gpio_bit_reset(GPIOA,GPIO_PIN_7)
#define GD_LED2_On gpio_bit_set(GPIOA,GPIO_PIN_8)
#define GD_LED2_Off gpio_bit_reset(GPIOA,GPIO_PIN_8)
#define GD_LED3_On gpio_bit_set(GPIOC,GPIO_PIN_6)
#define GD_LED3_Off gpio_bit_reset(GPIOC,GPIO_PIN_6)
#define GD_LED4_On gpio_bit_set(GPIOC,GPIO_PIN_7)
#define GD_LED4_Off gpio_bit_reset(GPIOC,GPIO_PIN_7)
//******************************************************************************
//* 函数名称 : GPIO_Config
//* 函数描述 : IO引脚的初始化
//* 输入参数 :
//* 参数描述 : 对应 IO口初始化及初始状态
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void gd_GPIO_init(void)
{
GD_RCU_GPIOA_INIT;
GD_RCU_GPIOC_INIT;
//*************************LED IO初始化************************************************
gpio_mode_set(GPIOA,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLDOWN,GPIO_PIN_7|GPIO_PIN_8);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7 | GPIO_PIN_8);
gpio_mode_set(GPIOC,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLDOWN,GPIO_PIN_6|GPIO_PIN_7);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
GD_LED1_Off;
GD_LED2_Off;
GD_LED3_Off;
GD_LED4_Off;
}
对于定时的配置:
第一步,选取合适的定时器,查看数据手册有定时器1/2, 定时器8/11, 定时器5/6,其中定时器5/6只能使用内部时钟源,故本次能使用的定时器只有剩余的4个,只是简单的定时功能,选择定时器8作为本次功能实现的定时器;
第二步,定时器的初始化,见代码;
第三步,编写中断处理函数。
定时器初始化代码:
//******************************************************************************
//* 函数名称 : gd_TIMER_init
//* 函数描述 : 定时器配置
//* 输入参数 :
//* 参数描述 : 定时器初始化配置
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void gd_TIMER_init(void)
{
gd_TIMER8_init(6400,100); //定时10ms
}
//******************************************************************************
//* 函数名称 : gd_TIMER8_init
//* 函数描述 : 定时器8配置
//* 输入参数 : psr,arr
//* 参数描述 : 定时器8初始化配置
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void gd_TIMER8_init(uint32_t psr,uint32_t arr)
{
timer_parameter_struct timer_initpara;
/* enable the peripherals clock */
rcu_periph_clock_enable(RCU_TIMER8);
/* deinit a TIMER */
timer_deinit(TIMER8);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER1 configuration */
timer_initpara.prescaler = psr-1;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = arr-1;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER8, &timer_initpara);
/* Timer8中断设置,优先级0*/
nvic_irq_enable(TIMER8_IRQn, 0);
/* 清除定时器中断标志位 */
timer_interrupt_flag_clear(TIMER8, TIMER_INT_FLAG_UP);
/*使能定时器中断*/
timer_interrupt_enable(TIMER8, TIMER_INT_UP);
// /* enable a TIMER */
// timer_enable(TIMER8);//这里暂时没有开启定时器,在最后的应用初始化开启
}
中断代码:
uint16_t LED_cnt=0;
typedef struct
{
uint8_t updata_flag; //LED更新标志位
uint8_t Mode; //LED模式
uint8_t state; //LED状态
}states;
states LED;
void TIMER8_IRQHandler(void)
{
if(SET == timer_interrupt_flag_get(TIMER8, TIMER_INT_UP))
{
timer_interrupt_flag_clear(TIMER8, TIMER_INT_UP);
LED_cnt++;
if(LED_cnt%50 == 0)
{
LED.state ++;
LED.state %= 4;
LED.updata_flag = 1;
}
if(LED_cnt%400 == 0)
{
LED.state = 0;
LED.Mode ++;
LED.Mode %= 4;
LED_cnt = 0;
}
}
}
应用代码:
//******************************************************************************
// 函数名称 : gd_App_Init
// 函数描述 : 应用级初始化操作
// 输入参数 :
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void gd_App_Init(void)
{
LED.updata_flag = 1;
timer_enable(TIMER8);
}
//******************************************************************************
// 函数名称 : App_LED
// 函数描述 : LED操作
// 输入参数 :
// 参数描述 : 无
// 输出参数 : 无
// 返回值 : 无
//******************************************************************************
void App_LED(uint8_t updata_flag,uint8_t Mode,uint8_t state)
{
if(updata_flag == 1)
{
GD_LED1_Off;
GD_LED2_Off;
GD_LED3_Off;
GD_LED4_Off;
switch(Mode)
{
case 0:
if(state == 0)
GD_LED1_On;
else if(state == 1)
GD_LED2_On;
else if(state == 2)
GD_LED3_On;
else if(state == 3)
GD_LED4_On;
break;
case 1:
if(state%2 == 0)
{
GD_LED1_On;
GD_LED2_On;
GD_LED3_On;
GD_LED4_On;
}
else
{
GD_LED1_Off;
GD_LED2_Off;
GD_LED3_Off;
GD_LED4_Off;
}
break;
case 2:
if(state%2 == 0)
{
GD_LED1_Off;
GD_LED2_On;
GD_LED3_Off;
GD_LED4_On;
}
else
{
GD_LED1_On;;
GD_LED2_Off;
GD_LED3_On;
GD_LED4_Off;
}
break;
case 3:
if(state == 0)
{
GD_LED1_On;
}
else if(state == 1)
{
GD_LED1_On;
GD_LED2_On;
}
else if(state == 2)
{
GD_LED1_On;
GD_LED2_On;
GD_LED3_On;
}
else if(state == 3)
{
GD_LED1_On;
GD_LED2_On;
GD_LED3_On;
GD_LED4_On;
}
break;
default:
break;
}
updata_flag = 0;
}
}
int main(void)
{
CK_SYS_int1 = rcu_clock_freq_get(CK_SYS);
CK_SYS_int2 = rcu_clock_freq_get(CK_AHB);
CK_SYS_int3 = rcu_clock_freq_get(CK_APB1);
CK_SYS_int4 = rcu_clock_freq_get(CK_APB2);
// /* configure systick */
// systick_config();
gd_GPIO_init();
gd_TIMER_init();
gd_App_Init();
while(1)
{
App_LED(LED.updata_flag,LED.Mode,LED.state);
}
}
现象如下:
|