任务介绍
本次任务选择的是任务三—— 按键和旋转编码器控制、点阵LED显示的人机接口模块,本次任务需要设计包含一个旋转编码器、多个(2个以上)按键以及点阵LED(5x7以上)的HMI模块,为方便搭配不同的核心板,我们设计的这个HMI模块需支持对核心板进行信息输入控制及核心板输出信息控制点阵LED的显示。
模块介绍
设计思路
本次设计的HMI模块本着集成效果的要求,将按键以及旋转编码器作为输入部分与LED矩阵作为输出部分集成在一个拓展板上,通过2.54的排针进行控制接口连接。
功能介绍
本次设计是HMI模块集成了一下功能:
两个轻触按键;
一个旋转编码器;
一个8*8矩阵LED显示。
硬件介绍
轻触按键使用的是6*6尺寸,相对来说这个尺寸的按键操作起来还是比较方便的;旋转编码器具有方向输出的效果,也具备轻触功能。LED显示采用的8*8矩阵模型,比较方形的设计比较方便进行显示,选取的是高亮的LED,具有功耗低,亮度大等特点,整体的矩阵控制使用的四两个串联的74HC595;接口最小化原则,按键及旋转编码器正好集中在一个1*5的排针上,LED矩阵控制及模块的供电通过另一个1*5的排针上。
设计框图
本次设计的人机接口模块,包含输入控制(一个旋转编码器和2个按键),输出显示为8*8 LED矩阵,为了尽可能的减少MCU的控制接口,LED矩阵接入74HC595控制,74HC595是一款串行输入/串行输出的移位寄存器,拥有8位移位寄存器和8位并行输出,这使得它在扩展数字IO端口时非常有用。它以串行的方式接收来自微控制器的数据,并能够控制多个输出引脚,从而达到用少量IO控制多个负载的目的。74HC595的工作原理基于两个主要部分:移位寄存器和锁存器。移位寄存器 :负责接收串行输入的数据。在每一个时钟脉冲的作用下,数据一位一位地向左移动。这个过程相当于在对数据进行“排队”。锁存器 :用于并行输出数据。一旦移位寄存器中的数据被完全接收并准备输出时,锁存器会同步这些数据并提供稳定输出。
原理图和PCB介绍
原理图
PCB
通过引入74HC595D,我们大大的将引脚数量减少,同时与输入控制引脚全部可以通过对称的两个1*5的2.54插座进行引出,本模块实现了输入和输出同时存在一个模块上,焊接后的实物图如下:
软件调试
本次设计的模块只能说是一个辅助模块,用于人机交互的,我们需要使用一款主控单元,通过杜邦线根据以下模块引脚定义进行适当的连接:
管脚属性 | 管脚名 | 管脚编号 | 管脚名 | 管脚属性 | |
P | 3.3V | H1-1 | H2-1 | FS-A | I/O |
P | GND | H1-2 | H2-2 | FS-B | I/O |
I/O | DIO | H1-3 | H2-3 | FS-D | I/O |
I/O | STCH | H1-4 | H2-4 | SW1 | I/O |
I/O | SHCH | H1-5 | H2-5 | SW2 | I/O |
这里我们选择了一款STM32C071的开发板作为本次测试验证的主控单元,根据功能需求连接如下:
我们使用STM32CubeMX生成初始化的工程,并启动输入采集的外部中断,74HC595D的通信接口我们连接到ST单片机的SPI串行接口上,并启动相关功能。
我们简单结合按键和LED举证实现功能:
初始状态下LED矩阵亮起第一排第一个灯;
随着旋转编码器的转动亮起的LED灯在同一行跳动,旋转编码器是可以识别方向的,正向跳动和反向跳动与旋转编码器的选装方向关联;
两个按键进行显示行数的切换。
主要代码介绍:
单个的LED控制函数,使用此函数可以打开8*8矩阵中的一个LED:
void HC595_Send_Byte(uint8_t num)
{
uint8_t i;
for(i = 0;i<8;i++)
{
if(num & 0x80)//取最高位 1000 0000
{
HC595_DS_SET;
}
else
{
HC595_DS_RESET;
}
HC595_SHCP_SET;
HAL_Delay(10);
HC595_SHCP_RESET;
HAL_Delay(10);
num <<=1;
}
}
void HC595_Send_Data(uint8_t Data_A,uint8_t Data_B)
{
HC595_Send_Byte(Data_B);
HC595_Send_Byte(Data_A);
HC595_STCP_SET;
HAL_Delay(10);
HC595_STCP_RESET;
HAL_Delay(10);
}
void HC595_Send_bit(uint8_t num)
{
uint8_t Data_A = 0x00;
uint8_t Data_B = 0x00;
uint8_t Data_X = 0x00;
uint8_t Data_Y = 0x00;
num = num%65;
if(num == 0)
{
Data_A = 0x00;
Data_B = 0x00;
}
else
{
Data_X = (num-1)%8;
Data_X = 0x01<<Data_X;
Data_Y = (num-1)/8;
Data_Y = 0x01<<Data_Y;
Data_A = Data_X;
Data_B = ~(0xff&Data_Y);
}
HC595_Send_Byte(Data_B);
HC595_Send_Byte(Data_A);
HC595_STCP_SET;
HAL_Delay(10);
HC595_STCP_RESET;
HAL_Delay(10);
}
按键的中断处理函数:
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_10)
{
data_flag = 1;
datax++;
if(datax > 8)
datax =1;
}
if(GPIO_Pin == GPIO_PIN_7)
{
data_flag = 1;
datax--;
if(datax == 0)
datax = 8;
}
}
旋转编码器的方向采集函数:
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_4)//FSB
{
}
if(GPIO_Pin == GPIO_PIN_5)//FSD
{
}
if(GPIO_Pin == GPIO_PIN_8)//FSA
{
if(READ_KEY_B == 1)
{
data_flag = 1;
datay++;
if(datay > 8)
datay =1;
}
else
{
data_flag = 1;
datay--;
if(datay == 0)
datay = 8;
}
}
}
模块调试效果图
心得体会
本次我们选择了一个人机接口模块的设计,并在其最低要求上进行了扩展,为了减少控制部分,我们引入了锁存器的控制,通过两个锁存器实现8*8LED矩阵的控制,通过这次的限时挑战我们初步完成了设计,并调试可以满足控制要求,不过由于时间限制,还是有一些不足的,比如模块外形的设计可以在小一点,增加有效的利用面积;引脚没有添加丝印指示,每次使用都需要找引脚图。后续的设计会参考这些细节上的不足,再接再厉。