STM32 矩阵式LED的实现方式与思路

*

一、写在前面
——以下内容皆为原创,转载请注明


电路如下图所示
这里写图片描述
一个4x3的矩阵式LED,行分别由GPIOB.6 GPIOB.5 GPIOB.4 GPIOB.3控制
列分别由GPIOB.9 GPIOB.8 GPIOB.7控制
需要达到达到显示效果:
1、全部点亮
2、点亮D2 D4 D6 D8 D10 D12
3、点亮D2 D8 D10 D12
4、点亮D4 D6 D10 D12
5、点亮D10
上面五种效果都需要当对应按键按下时,对应的LED熄灭,抬手后重新点亮
于是乎MODE2就有了7种效果
1、MODE2全亮
2、MODE2熄灭D2
3、MODE2熄灭D4
4、MODE2熄灭D6
5、MODE2熄灭D8
6、MODE2熄灭D10
7、MODE2熄灭D12
我将以MODE2 的显示效果来说明。
我当时首先想到的就是采用单点点亮的方式去刷新来达到显示效果;
对于MODE2来说需要6个步骤
点亮 D2 –>点亮D4–>点亮D6–>点亮D8–>点亮D10–>点亮D12;
测试出来的效果是能满足要求;但是问题 在于,系统需要做其他任务(典型性的裸奔前后台系统),就会导致始终都是最后一个显示的亮度很高—亮度不均匀;
最后确定,采用定时器中断去执行这个点亮LED的任务;这样就能解决亮度不均匀的问题;
在决定用定时器去做这个事情的时候,我就决定不再采用单个点亮的方式去实现,而是采用一次点亮一列,这样所有的效果都会只需要3次就能完成;
部分代码如下:

     switch(Pres)
    {
            case 0://MODE2 全亮
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                GPIOB->ODR |= 0x000001A8;//点亮第一列

                GPIOB->ODR &= 0xFFFFFC07;   
                GPIOB->ODR |= 0x000002D0;//点亮第二列

                GPIOB->ODR &= 0xFFFFFC07;
                GPIOB->ODR |= 0x00000328;//点亮第三列

                GPIOB->ODR &= 0xFFFFFC07;//熄灭所有 
                break;
            }
}

这段代码是MODE2全部点亮的操作;但是这样的实现方式问题很大;
刚开始测试,似乎满足了我所有的需求;于是按照这种方式将后面其他MODE的代码全部写出;
测试代码的时候问题就来了,这个亮度太低了;
最开始我以为是频率不够,导致LED的实际占空比太低了;于是尝试提升占空比;结果发现并没有什么用;又尝试了降低限流电阻,也没有什么用
问题出在哪里呢?
想不到,就用示波器看,发现点亮LED的脉冲实在是小的可怜;
现在在回头看这段代码

     switch(Pres)
    {
            case 0://MODE2 全亮
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                GPIOB->ODR |= 0x000001A8;//点亮第一列

                GPIOB->ODR &= 0xFFFFFC07;   
                GPIOB->ODR |= 0x000002D0;//点亮第二列

                GPIOB->ODR &= 0xFFFFFC07;
                GPIOB->ODR |= 0x00000328;//点亮第三列

                GPIOB->ODR &= 0xFFFFFC07;//熄灭所有 //问题就在这里
                break;
            }
}

每次点亮一列LED之后下一步就是把这一列熄灭;时间太短了;
那应该怎么延长?
我首先想到的就是延时,但是这种想法简直就是愚蠢之极;
因为是在中断服务函数中处理做这个事情,而且这个中断在系统中触发的频率很 高,这样就会导致主函数中的任务就会经常响应很慢;
最后,我决定中断服务函数中,每次只显示一列;显示下一列的时候才把上一列的状态清除,这样每一列的电平置位的时间就是一个中断周期,并且每一列都一样;
下面附上MODE2的全部代码

static void LED_Show_Two(uint8_t Pres,uint8_t Cnt)
{
    switch(Pres)
    {
            case 0://MODE2 全亮
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x000001A8;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x000002D0;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000328;
                        break;
                    }
                    default:break;
                }
                break;
            }
            case 2: //MODE3 2键按下
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x000001A8;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x00000290;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000328;
                        break;
                    }
                    default:break;
                }
                break;
            }
            case 4://MODE2 4键按下
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x00000188;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x000002D0;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000328;
                        break;
                    }
                    default:break;
                }
                break;
            }
            case 6://MODE2 6键按下
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x000001A8;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x000002D0;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000308;
                        break;
                    }
                    default:break;
                }
                break;
            }
            case 8://MODE2 8键按下
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x000001A8;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x000002C0;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000328;
                        break;
                    }
                    default:break;
                }
                break;
            }
            case 10:
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x000001A0;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x000002D0;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000328;
                    }
                    default:break;
                }
                break;
            }
            case 12:
            {
                GPIOB->ODR &= 0xFFFFFC07;               
                switch(Cnt)
                {
                    case 0:
                    {
                        GPIOB->ODR |= 0x000001A8;
                        break;
                    }
                    case 1:
                    {
                        GPIOB->ODR |= 0x000002D0;
                        break;
                    }
                    case 2:
                    {
                        GPIOB->ODR |= 0x00000320;
                        break;
                    }
                    default:break;
                }
                break;
            }
            default:break;
  }
}

到这里,我所需要的功能都实现了,但是有个问题,代码太长了;至于怎么优化,我还没找到方法
*

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要使用STM32控制矩阵按键来控制LED,您可以按照以下步骤进行操作: 1. 首先,连接矩阵按键和LEDSTM32微控制器。确保按键矩阵的行和列引脚连接到适当的GPIO引脚,并将LED连接到另外的GPIO引脚。 2. 在STM32上配置GPIO引脚作为输入和输出。使用STM32的开发工具(如STM32CubeMX)或编程语言(如C语言)配置相应的引脚。 3. 在程序中实现矩阵按键扫描。使用循环遍历按键矩阵的每个行和列,检测是否有按键按下。可以使用外部中断或定时器中断来触发扫描。 4. 根据按键状态控制LED。根据扫描结果,确定哪个按键按下,并相应地控制对应的LED引脚输出高电平或低电平来点亮或熄灭LED。 下面是一个示例代码片段,展示了如何在STM32实现矩阵按键控制LED的功能(使用STM32 HAL库): ```c #include "stm32f4xx_hal.h" // 定义矩阵按键行和列数 #define ROWS 4 #define COLS 4 // 定义矩阵按键的行和列引脚 GPIO_TypeDef* ROW_PINS[ROWS] = {GPIOA, GPIOB, GPIOC, GPIOD}; uint16_t ROW_PINS_NUM[ROWS] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3}; GPIO_TypeDef* COL_PINS[COLS] = {GPIOE, GPIOF, GPIOG, GPIOH}; uint16_t COL_PINS_NUM[COLS] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3}; // 定义LED引脚 GPIO_TypeDef* LED_PORT = GPIOI; uint16_t LED_PIN = GPIO_PIN_0; // 定义矩阵按键状态数组 uint8_t keyStatus[ROWS][COLS] = {0}; // 矩阵按键扫描函数 void scanKeypad(void) { for (int row = 0; row < ROWS; row++) { HAL_GPIO_WritePin(ROW_PINS[row], ROW_PINS_NUM[row], GPIO_PIN_RESET); for (int col = 0; col < COLS; col++) { if (HAL_GPIO_ReadPin(COL_PINS[col], COL_PINS_NUM[col]) == GPIO_PIN_RESET) { keyStatus[row][col] = 1; // 按键按下 } else { keyStatus[row][col] = 0; // 按键未按下 } } HAL_GPIO_WritePin(ROW_PINS[row], ROW_PINS_NUM[row], GPIO_PIN_SET); } } // 控制LED函数 void controlLED(void) { if (keyStatus[0][0] == 1) { HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); // 点亮LED } else { HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); // 熄灭LED } } int main(void) { HAL_Init(); // 初始化GPIO引脚配置和外部中断/定时器中断配置 while (1) { scanKeypad(); controlLED(); } } ``` 请注意,以上代码仅为示例,您需要根据您的具体硬件和需求进行适当的修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值