默认情况下,高电平点亮LED,低电平熄灭。
修改的地方
1、兼容hal库和标准库(新增)
在led.c的起始处的定义了一个宏(后期会移到其他地方),给他赋值0就是使用标准库,使用hal库的话就给他改成1,这里不用担心,放心改,后面已经使用预处理处理了了。
2、led_cfg_t结构体(删去)
把原来的时钟删去了,因为时钟只在初始化GPIO的时候用到,而且hal的GPIO初始化都是直接生成的,所以找到了其他解决办法来代替这个位置,就给丫干掉了!
至于GPIO初始化时钟怎么玩的,看下文!
3、注册led端口及引脚(修改)
注册led的地方也换位置了喔,由原来在led_init()函数里的局部变量改为全局变量(有点点费内存就是了)
4、预处理(新增)
为了兼容 hal,在各个位置加了预处理,不用管他
5、p_led_task函数(修改)
因为该函数的返回值是一个指针,所以把它函数名改成了“p_led_task”,给丫加了个前缀"p_",意为返回值为指针类型。另外节省行数,把if else改成了三段式,不影响,跟原来食用方法一样
6、 v_led_task函数(新增)
如你所见这个函数和上面那个长的及其相像,没错这俩玩意实现的功能是一样的,看到这个“v_”的前缀,,想必会明白该函数返回值为void也就是没有返回值。
是的没错,就是这样,这个是直接操作gpio口的高低电平,并没有返回指针,至于我收起来的那部分也无需管,就是为了兼容hal的
7、led_init函数(修改)
众所周知hal用不到这玩意儿。。。。。所以第一个修改的地方就是用预处理括起来。(不用管不用管),唯一起作用的就是把led灯全给丫关上。
(这里不给放全部代码了,两个文件的代码插文章末尾)
然后看我给开时钟那里做的手脚。
我先用要初始化的端口减去GPIOA,就得到了端口号的偏移量,然后给丫右移10位,把字节单位转为字单位,就是对应的时钟的偏移量的,然后再用GPIOA的时钟左移这个偏移量就是开启当前要初始化的端口的时钟了。????这里看不懂,其实我也不懂,我们不妨问问神奇的海螺。
8、led_test函数(新增)
这就是把上篇文章的主函数里运行的玩意挪了过来,其功能如注释所言,注册多少个led灯,,就跑这些数目的流水灯,同样兼容hal库
源码
led.c
#include "led.h"
//点灯:默认是0点亮 1熄灭
//如果使用HAL开发则把下面的0改成1,使用标准库则无需管
#define HAL_Lib 0//默认标准库\
0是标准库 \
1为hal库
/***************************************************************************/
//根据需求在该数组进行注册
led_cfg_t led_cfg[] =
{
/*端口*/ /*引脚*/
{led1_port, led1_pin},
//.....
};
/***************************************************************************/
//在以下区间定义开关灯函数/
void led1_on(void)
{
#if HAL_Lib
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
// HAL_GPIO_WritePin(led1_port,led1_pin,GPIO_PIN_SET);//1点亮
HAL_GPIO_WritePin(led1_port, led1_pin, GPIO_PIN_RESET);//0点亮
#else
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
// GPIO_SetBits(led1_port,led1_pin);//1点亮
GPIO_ResetBits(led1_port,led1_pin); //0点亮
#endif
}
void led1_off(void)
{
#if HAL_Lib
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
HAL_GPIO_WritePin(led1_port,led1_pin,GPIO_PIN_SET);//1熄灭
// HAL_GPIO_WritePin(led1_port, led1_pin, GPIO_PIN_RESET);//0熄灭
#else
/*根据电路图看是高电平熄灭还是低电平熄灭选择注释掉*/
GPIO_SetBits(led1_port,led1_pin); //1熄灭
// GPIO_ResetBits(led1_port,led1_pin); //0熄灭
#endif
}
//可参考以上格式修改或添加
/*添加完之后在下面的 led_on_pointer[] 和 led_off_pointer [] 数组里分别进行注册*/
//...
/
/*定义函数指针类型*/
typedef void(* led_function_pointer)(void);
//在这里的下面注册 led_on,只需函数名即可
static led_function_pointer led_on_pointer [] =
{
led1_on,
//可参考以上格式修改或添加
//...
};
//在这里的下面注册 led_off,只需函数名即可
static led_function_pointer led_off_pointer [] =
{
led1_off,
//可参考以上格式修改或添加
//...
};
/
下面的函数不用改动喔!!!!///
//led任务:对外的接口函数
//参数1: led号,选择第几个led,这个是要按照上面的 函数指针数组里注册的顺序填写喔
//参数2: led的状态,给1亮,给0灭
//返回值: 返回值是一个函数指针,指向一个 返回值为 void 类型指针、参数为 void 的函数
void (* p_led_task(unsigned char led_num, unsigned char led_sta))(void)
{
return (led_sta == 1) ? (led_on_pointer[led_num]) : (led_off_pointer[led_num]);
}
/
//这个函数也不要动
//这个是直接操作GPIO点亮和熄灭灯,不使用指针
//参数1: led号,选择第几个led,这个是要按照上面的 函数指针数组里注册的顺序填写喔
//参数2: led的状态,给1亮,给0灭
//返回值: 无返回值
void v_led_task(unsigned char led_num, unsigned char led_sta)
{
#if HAL_Lib
led_sta \
? \
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
//1点亮
// HAL_GPIO_WritePin(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin,GPIO_PIN_SET)\
//0点亮
HAL_GPIO_WritePin(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin,GPIO_PIN_RESET)\
:\
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
//1熄灭
HAL_GPIO_WritePin(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin,GPIO_PIN_SET);\
//0熄灭
// HAL_GPIO_WritePin(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin,GPIO_PIN_RESET);
#else
led_sta \
? \
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
//1点亮
// GPIO_SetBits(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin)\
//0点亮
GPIO_ResetBits(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin)\
:\
/*根据电路图看是高电平点亮还是低电平点亮选择注释掉*/
//1熄灭
GPIO_SetBits(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin);\
//0熄灭
// GPIO_ResetBits(led_cfg[led_num].Led_Port,led_cfg[led_num].Led_Pin);
#endif
}
//LED初始化
void led_init(void)
{
#if HAL_Lib
#else
/*只需要在上面注册,下面的东西不要动喔*/
GPIO_InitTypeDef GPIO_InitStruct;
#endif
led_function_pointer led_action;
for(int i = 0; i<led_cfg_num; i++)
{
#if HAL_Lib
#else
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA<<
((led_cfg[i].Led_Port - GPIOA)>>10),
ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=led_cfg[i].Led_Pin;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(led_cfg[i].Led_Port,&GPIO_InitStruct);
#endif
// 熄灭所有的led
led_action = p_led_task(i,0);
led_action();
}
}
//注册多少个LED就流水多少个LED
void led_test(void)
{
led_function_pointer led_action;
while(1)
{
for(int i = 0; i< led_cfg_num; i++)
{
led_action = p_led_task(i,1);
led_action();
#if HAL_Lib
HAL_Delay(1000);
#else
delay_ms(1000);
#endif
led_action = p_led_task(i,0);
led_action();
#if HAL_Lib
HAL_Delay(1000);
#else
delay_ms(1000);
#endif
}
}
}
led.h
#ifndef _LED_H_
#define _LED_H_
#if HAL_Lib
#include "stm32f1xx_hal.h"
#else
#include "system.h"
#include "delay.h"
#endif
/*需要配置的led的数量,这里不需要改喔*/
#define led_cfg_num sizeof(led_cfg)/sizeof(led_cfg[0])
可根据需求修改下方宏
#define led1_port GPIOC //端口
#if HAL_Lib
#define led1_pin GPIO_PIN_0 //引脚
#else
#define led1_pin GPIO_Pin_0 //引脚
#endif
//可参考以上格式修改或添加
/*添加完之后在 led.c 里的 led_cfg[] 数组里进行注册*/
//...
/
//led 配置结构体
typedef struct
{
GPIO_TypeDef *Led_Port; //端口
uint16_t Led_Pin; //引脚
}led_cfg_t;
//LED初始化
void led_init(void);
//LED任务:返回值是指针
void (* p_led_task(unsigned char led_num, unsigned char led_sta))(void);
//LED任务:直接操作GPIO,无返回值
void v_led_task(unsigned char led_num, unsigned char led_sta);
//LED测试:注册多少个LED就流水多少个LED
void led_test(void);
#endif