相信各位在学习STM32时也会从LED灯开始,下面小编给大家展示小编自主完成的流水灯吧。
通过查阅原理图我们很容易判断出这是一个共阳LED,因此每个LED灯应该是0有效,即输入0就点亮LED灯。
//定义LED的状态 LED_ON表示LED亮 LED_OFF表示LED灭
enum LED_STATE {LED_ON,LED_OFF};
//定义LED的位置 LED0为无效位置 LED1表示LED1位置 LED2表示LED2位置……
enum LED_NUM{LED0,LED1,LED2,LED3,LED4,LED5,LED6,LED7,LED8};
初始化函数中,我们需要初始化的有系统、相应的时钟、GPIO引脚、GPIO的频率、GPIO的模式。在点灯过程中,我们需要将GPIOC时钟设置成使能状态、选择引脚为Pin0-Pin7(这里选择所有引脚影响也不大,毕竟我们只需要使用Pin0-Pin7)、将GPIOC的频率设置成10MHz、同时将GPIOC模式设置成推挽输出。
/**
* @brief GPIO initalization(GPIO初始化)
* @param none
* @retval none
*
*/
void LED_GPIO_init(void)
{
//定义一个GPIO_InitTypeDef类型的结构体变量,用于初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
///系统初始化函数
SystemInit();
//RCC_APB2PeriphClockCmd()函数用于 使能 或 失能 APB2外设时钟
// 参数1:RCC_APB2Periph是门控APB2外设时钟(下面表示选择GPIOC时钟) 参数2:New State设置外设时钟新状态 ENABLE-使能状态 DISABLE-失能状态
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
//GPIO初始化
//选择所有的GPIO的引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
//GPIO速度配置 可供选择的速度有10MHz、2MHz、50MHz
//-下面我们选择的是10MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
//设置GPIO的工作模式 8种工作模式,分别是GPIO_Mode_AIN(模拟输入)、GPIO_Mode_IN_FLOATING(输入浮空)
//GPIO_Mode_IPD(输入下拉)、GPIO_Mode_IPU(输入上拉)、GPIO_Mode_Out_OD(开漏输出)、GPIO_Mode_Out_PP(推挽输出)
//GPIO_Mode_AF_OD(开漏复用功能)、GPIO_Mode_AF_PP(推挽复用功能)
//-下面我们选择的是推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//GPIO_Init函数是初始化指定外设GPIOx寄存器
//参数1:GPIOx-选择对应的GPIOx寄存器 参数2:GPIO_InitStruct指向包含外设GPIO配置信息的指针
GPIO_Init(GPIOC,&GPIO_InitStructure);
}
在LED控制函数中,我们需要注意的是GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)函数,该函数一共有三个参数,参数1适用于选定GPIO的组 ,也就是GPIOA、GPIOB、GPIOC……,参数2是GPIO组的引脚,也就是Pin0、Pin1、Pin2、Pin3……,参数3就是需要写入的数值,不过这里的BitVal是一个枚举类型,它有两个值,分别是Bit_RESET(引脚复位,相当于输入0)、Bit_SET(引脚不复位,相当于输入1)。
在控制函数LED_ctrl()中,小编使用switch来选择某一个LED灯进行控制,再通过GPIO_WriteBit()函数来点亮或者是熄灭LED灯
/**
* @brief control the bright state of LED(控制LED的亮灭状态)
* @param LED_NUM:location of LED(LED的位置)
* @arg LED0: incalid position(无效的位置)
* @arg LED1: control state of LED0(控制LED1)
* @arg LED2: control state of LED0(控制LED2)
* @arg LED3: control state of LED0(控制LED3)
* @arg LED4: control state of LED0(控制LED4)
* @arg LED5: control state of LED0(控制LED5)
* @arg LED6: control state of LED0(控制LED6)
* @arg LED7: control state of LED0(控制LED7)
* @arg LED8: control state of LED0(控制LED8)
* @param LED_STATE: state of LED(LED的状态)
* @arg LED_ON:the bright state of LED(LED的点亮状态)
* @arg LED_OFF:the extinguishingstate of led(LED的灭状态)
* @retval none
*/
void LED_ctrl(int LED_NUM,int LED_STATE){
//使用switch语句判断需要控制灯的位置
//再通过向对应引脚写入 复位(Bit_RESET) 或 不复位(Bit_RESET) 来控制LED的亮灭状态
switch(LED_NUM){
case LED1: GPIO_WriteBit(GPIOC,GPIO_Pin_0,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED1
case LED2: GPIO_WriteBit(GPIOC,GPIO_Pin_1,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED2
case LED3: GPIO_WriteBit(GPIOC,GPIO_Pin_2,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED3
case LED4: GPIO_WriteBit(GPIOC,GPIO_Pin_3,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED4
case LED5: GPIO_WriteBit(GPIOC,GPIO_Pin_4,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED5
case LED6: GPIO_WriteBit(GPIOC,GPIO_Pin_5,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED6
case LED7: GPIO_WriteBit(GPIOC,GPIO_Pin_6,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED7
case LED8: GPIO_WriteBit(GPIOC,GPIO_Pin_7,(LED_STATE==0?Bit_RESET:Bit_SET));break;//控制LED8
default: break;//排除可能出现的干扰
}
}
每一次点亮一个LED灯时,需要关闭上一个LED灯,这里小编采用关闭所有LED灯操作,既能够完成关闭上一个灯操作,也能够排除其他不必要的干扰。点亮一个LED灯后需要进行延时一定时间,不然点亮LED就只有一瞬间,我们人眼是无法看到这一瞬间的。这里还需要注意的是使用循环进行延时,延时时间比较短,(大概1ms约等于10次循环,1ms约等于1200次循环,准确的时间还需要自己测试哈)因此,小编这里采用的数据也比较大。
/**
* @brief flowing water LED light by using cycle(使用循环实现流水灯)
* @param none
* @retval none
*
*/
void LED_water_use_for(void)
{
//定义一个静态变量用于记录LED灯的位置
//这里需要注意的是由于LED0是无效的,因此从LED1开始,也相当于将led_location的初始值赋值为1
static int led_location = 1;
//定义延时循环控制变量
u32 i = 0;
//每一次点灯的时候都关闭所有灯,避免出现同时点亮多个LED灯
LED_all_off();
//点亮本次需要点亮的LED灯
LED_ctrl(led_location,LED_ON);
//使用while循环达到延时的效果
while(i < 6000000){
i++;
}
//移动到下一个点灯位置,由于只有8个LED灯所有最多只能加到9
if(++led_location == 9) led_location = 1;
}
(具体定时器配置相关的内容,大家可以查看STM32-配置SysTick定时器)
/*
* @brief microsecond dealy(微秒级延时)
* @param i:time to be delayed(延时时间)
* @retval none
*/
void delay_us(u32 i){
//u32表示uint32_t数据类型
u32 temp = 0;
SysTick->LOAD = 9*i;
//使能状态,减到0是无动作,采用的是外部时钟源
SysTick->CTRL = 1;
//清空计数器
SysTick->VAL = 0;
do{
temp = SysTick->CTRL;//获取当前计数值
}while((temp&0x01) && (!(temp&(1<<16))));
SysTick->CTRL = 0;//关闭计数器
SysTick->VAL = 0;//清空计数器
}
/*
* @brief millisecond dealy(毫秒级延时)
* @param i:time to be delayed(延时时间)
* @retval none
*/
void dealy_ms(u32 i){
delay_us(i*1000);
}
(由于使用循环延时的流水灯与使用定时器延时实现的流水灯思路差不多,小编在次就不再赘述。)
/**
* @brief flowing water LED light by using delay function(使用延时函数实现流水灯)
* @param i:tmie to be delayed(需要延时的时间)
* @retval none
*
*/
void LED_water_use_dealy(u32 i)
{
//定义一个静态变量用于记录LED灯的位置
//这里需要注意的是由于LED0是无效的,因此从LED1开始,也相当于将led_location的初始值赋值为1
static int led_location = 1;
//每一次点灯的时候都关闭所有灯,避免出现同时点亮多个LED灯
LED_all_off();
//点亮本次需要点亮的LED灯
LED_ctrl(led_location,LED_ON);
//使用延时函数延时
dealy_ms(i);
//移动到下一个点灯位置,由于只有8个LED灯所有最多只能加到9
if(++led_location == 9) led_location = 1;
}
小编个人感觉STM32开发板与51开发板使用的思路上还是差不多的,但STM32相对复杂,能够使用的库函数比较多,了解并且熟悉STM32的库函数,那么就能彻底掌握STM32相关学习了。
最后,冲啊!奥利给!让我们一举拿下STM32!