LED驱动方式
LED驱动方式目前接触的就几个,最基础的两个灌电流和源电流驱动,然后是矩阵LED,数码管其实也算是矩阵的一种。
我之前一直在想一个问题,有没有一种方法可以在一个地方统一管理这些IO引脚呢?于是就有了之前GPIO口里面预留的三个函数,可以用一个for循环同时控制刷新多个灯,适用性可能不是很强,只是突然想到的一个东西不想浪费掉这些灵感,记录下来说不定后续有更好的方法优化一下。
流水灯驱动
假设现在板子上有3个灯,或者不用假设🤓之前设计的这个开发板就是预留了6个LED,其中3个是高电平驱动另外3个是低电平驱动,没有内置电路,通过引出排针,可以用任意IO口接到这上面来驱动LED。
我要实现流水灯的话,每次只亮1颗LED,从左到右,到了尽头再换一个方向继续,循环。
可以随便挑6个GPIO引脚:(先提前说好,如果接的仿真芯片,非常不推荐接PA0和PA2🤒如果PA0和PA2有变动的话直接中断仿真的)
- PA1
- PB2
- PB5
- PC3
- PA6
- PB4
前面三个接高电平驱动的LED,后面三个接低电平驱动的LED。
对应的任务结构体:
typedef struct
{
unsigned char Status;
}LED_Task;
目前也没有特殊的需求,先用一个变量记录当前灯状态这种。合泰的编译器支持bit变量的,但是不支持把bit变量放到结构体里面。
如果后面有心情的话,可以做一个流水灯带拖尾的效果,就是相当于把前面讲的那个时基模拟PWM拿过来改一下。
还有一个,同样规格的灯需要在头文件记录一下数目,后面多个地方会用到:
#define Normal_LED_Num 6
LED的GPIO映射关系
先定义一个常量的二维数组,这样子就可以很快能查到并且修改对应的映射关系。
#define LED_1 0
#define LED_2 1
#define LED_3 2
#define LED_4 3
#define LED_5 4
#define LED_6 5
const unsigned char LED_Map[Normal_LED_Num][3] =
{
{LED_1, GPIOA, Pin1,},
{LED_2, GPIOB, Pin2,},
{LED_3, GPIOB, Pin5,},
{LED_4, GPIOC, Pin3,},
{LED_5, GPIOA, Pin6,},
{LED_6, GPIOB, Pin4,},
};
其实仔细一看会发现,这个二维数组的第0个参数其实可有可无,加上只是为了方便对电路图。
初始化
LED_Task LED[Normal_LED_Num];
unsigned char LED_Move_Status;
bit LED_Director;
void LED_Init()
{
unsigned char i;
for(i = 0; i < Normal_LED_Num; i++)
{
GPIO_Map_Control(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_Output);
if(i < 3)
GPIO_Map_Write(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_Low);
else
GPIO_Map_Write(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_High);
}
LED_Move_Status = 0x01;
LED_Director = 1;
}
灯状态刷新
这个灯效对速度没有要求,所以可以放置在下面位置刷新之后,马上跟一个灯状态刷新。
void LED_Display()
{
unsigned char i;
unsigned char index = 0x01;
for(i = 0; i < Normal_LED_Num; i++)
{
LED[i].Status = !!(LED_Move_Status & index);
if(LED[i].Status != 0)
{
if(i < 3)
{
GPIO_Map_Write(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_High);
}
else
{
GPIO_Map_Write(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_Low);
}
}
else
{
if(i < 3)
{
GPIO_Map_Write(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_Low);
}
else
{
GPIO_Map_Write(LED_Map[i][GPIO_Map_Group], LED_Map[i][GPIO_Map_Pin], IO_High);
}
}
index <<= 1;
}
}
位置刷新
这个可以ms~s级别来刷新这个状态。主要是操作一个变量,到了边界之后就换一个方向。
void LED_Dir_Update()
{
if(LED_Director == 1) /* 右 */
{
if(LED_Move_Status == 0x01)
{
LED_Director = 0;
LED_Move_Status <<= 1;
}
else
{
LED_Move_Status >>= 1;
}
}
else /* 左 */
{
if(LED_Move_Status == 0x20)
{
LED_Director = 1;
LED_Move_Status >>= 1;
}
else
{
LED_Move_Status <<= 1;
}
}
if(LED_Move_Status > 0x20)
LED_Move_Status = 0x01;
LED_Display();
}
效果
暂时不知道怎么上传😂