要写一个程序首先得明白写程序的目的,也就是需要实现的是什么,然后在进一步分析需要用到什么模块和主控的哪些功能引脚,就比如一个最简单的基于stm32的led控制程序:首先我们需要他点亮,点亮了之后可以闪烁,然后为了高级一点再加一个流水灯,也就是几个led依次闪烁。
第一步:led的控制需要用到的是GPIO引脚和时钟使能,需要将引脚拉高才能点亮,就需要加上GPIO的启动文件以及CORE文件,core应该就是启动文件,这个待后续了解。
第二步,初始化led对应的GPIO口,比如我的板子的4个led接的就是PG6、PA8、PB8和PB9,首先定义一个自己的GPIO初始化结构体,然后使能对应GPIO的时钟,这里的GPIO全都是挂接在APB2这个时钟上的,所以使能这四个I/O口的时钟即可,然后就是配置GPIO了,这里配置是使用的32启动程序中自带的结构体,当然被我们重定义名称了。其中结构体中需要配置是引脚(GPIO_Pin)、I/O口的速度(GPIO_Speed)、I/O口的输出模式(GPIO_Mode)、以及引脚初始化(GPIO_Init)。
第三步,写一个让i/o口输出低电平(点亮)的函数,函数中只需要用到GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)这个系统函数,这个函数的意思就是将对应引脚的电平拉低,一共写是三个,这里写三个是因为有两个引脚的GPIO是一样的,所以 |(或)一下就可以了,意思是该函数运行,四个灯都亮。代码如下:
void leds_on(void)
{
//LED指示灯D1的引脚(PG6)输出低电平,即点亮D1
GPIO_ResetBits(GPIOG,GPIO_Pin_6);
//LED指示灯D2的引脚(PA8)输出低电平,即点亮D2
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
//LED指示灯D3、D4的引脚(PB8 PB9)输出低电平,即点亮D3、D4
GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9);
}
如果想写全不亮的函数则用GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)这个函数,将电平拉高,我这里的led是低电平发光的。
第四步,写一个带参数输入的函数,参数为LED的引脚编号。引脚编号需要在.h文件中定义,代码如下:
#define LED_1 (GPIO_Pin_6 | (1UL<<16))
#define LED_2 (GPIO_Pin_8 | (2UL<<16))
#define LED_3 (GPIO_Pin_8 | (3UL<<16))
#define LED_4 (GPIO_Pin_9 | (4UL<<16))
其中1UL<<16是: LED 指示灯对应的引脚分属不同的数据端口,可能会存在的数据端口不同但引脚编号一样的情况(如LED2 和 LED3,引脚编号都是 8,但分别属于数据端口 GPIOA和 GPIOB),为了区分,在高 16 位上增加了和 LED 对应的编号。查看管脚定义可以知道,引脚是被强制转换为16进制的地址值,所以在高16上做标记不会有影响。然后在函数中定义一个无符号的16位整数型变量,用于存放引脚的编号,&(与)上0xffff取到高16位的编号,然后做判断将GPIOx的BSRR(这里只用到低16位,端口为设置寄存器,拉高是熄灭)赋值对应编号,用于熄灭LED
代码如下:
/***************************************************************************
* 描 述 : 熄灭一个指定的LED
* 参 数 : [IN]led_idx:LED 对应的引脚编号
* 返回值 : 无
***************************************************************************/
void led_off(uint32_t led_idx)
{
//取得引脚的编号
uint16_t pin_num = (uint16_t)(led_idx&0xFFFF);
//区分数据端口,并驱动pin_num对应的引脚输出高电平,即熄灭对应的LED
if(led_idx == LED_1)GPIOG->BSRR = pin_num;
if(led_idx == LED_2)GPIOA->BSRR = pin_num;
if((led_idx == LED_3) || (led_idx == LED_4))
{
GPIOB->BSRR = pin_num;
}
}
第五步,另起一个点亮led带参数的函数,与上述函数一样,不同点只在于用的寄存器不同,上述用的BSRR(置位寄存器),这里点亮的话需要用到GPIO的BRR(复位寄存器),代码如下:
/***************************************************************************
* 描 述 : 点亮一个指定的LED
* 参 数 : [IN]led_idx:LED 对应的引脚编号
* 返回值 : 无
***************************************************************************/
void led_on(uint32_t led_idx)
{
//取得引脚的编号
uint16_t pin_num = (uint16_t)(led_idx&0xFFFF);
//区分数据端口,并驱动pin_num对应的引脚输出低电平,即点亮对应的LED
if(led_idx == LED_1)GPIOG->BRR = pin_num;
if(led_idx == LED_2)GPIOA->BRR = pin_num;
if((led_idx == LED_3) || (led_idx == LED_4))
{
GPIOB->BRR = pin_num;
}
}
第六步,在主函数中调用这些函数就行了。这样一个LED灯的控制程序就完成了;比如我想让LED1亮,则调用led_on(LED1)即可。
简单提一下,翻转LED灯,使用GPIO的ODR寄存器,使用异或运算来让对应的I/O状态翻转,代码贴上:
/***************************************************************************
* 描 述 : 翻转一个指定的LED的状态
* 参 数 : [IN]led_idx:LED 对应的引脚编号
* 返回值 : 无
***************************************************************************/
void led_toggle(uint32_t led_idx)
{
//取得引脚的编号
uint16_t pin_num = (uint16_t)(led_idx&0xFFFF);
//区分数据端口,通过对ODR寄存器相应的位异或运算翻转对应的IO输出状态
if(led_idx == LED_1)
{
GPIOG->ODR ^= pin_num;
}
if(led_idx == LED_2)
{
GPIOA->ODR ^= pin_num;
}
if((led_idx == LED_3) || (led_idx == LED_4))
{
GPIOB->ODR ^= pin_num;
}
}
以上为学习的总结,不到之处望指正。感谢!!