STM32+TM1620B实现按键识别和数码管驱动
各位好,小弟在学习了B站江科大的STM32的教程后,自己搞了个板子,实现TM1620B的按键识别和数码管驱动,现跟大家分享下原理和代码。
1、原理
单片机用的是STM32F103C8T6,3个2位7段共阴极数码管,6个按键,1个TM1620B。
其中6位数码管的公共端分别接到TM1620B的GR1~6上,因此TM1620B需要是6位7段的模式,每个数码管的a~g接到TM1620B的SEG1~6以及SEG12上。
按键的公共端接到TM1620的K2上,按键的另一端分别接到SEG1~6上。
2、程序实现
(1)TM1620B的初始化
#define TM1620B_PORT GPIOB
#define TM1620B_STB GPIO_Pin_3
//在上升或下降沿初始化串行接口,随后等待接收指令。
//STB 为低后的第一个字节作为指令,当处理指令时,当前其它处理被终止。
//当STB 为高时,CLK 被忽略
#define TM1620B_CLK GPIO_Pin_4
//在上升沿输入/输出串行数据
#define TM1620B_DIO GPIO_Pin_5
//在时钟上升沿输入/输出串行数据,从低位开始
STM32的PB2~5接TM1620B的STB、CLK、DIO。
/*!
* @brief 初始化TM1620B的管脚
* @param
*/
void TM1620B_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //关闭JTAG功能(PB3/4),只使用SWD(PA13/14)调试
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE );
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
GPIO_InitStruct.GPIO_Pin = TM1620B_STB | TM1620B_CLK | TM1620B_DIO ;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz ;
GPIO_Init( TM1620B_PORT , &GPIO_InitStruct );
TM1620B_W_DIO(1);
TM1620B_W_CLK(1);
TM1620B_W_STB(1); //常态都拉高
}
①PB3和4默认不是GPIO的功能,需要改一下。STM32F103系列PB3 PB4重映射成正常io口_stm32f103 pb3-CSDN博客
②IIC开漏输出。
③开始3个管脚都拉高。
(2)发送一个字节
①读写3个管脚
/*********************************读写TM1620B管脚********************************************/
void TM1620B_W_STB( uint8_t BitValue )
{
GPIO_WriteBit(TM1620B_PORT , TM1620B_STB , (BitAction)BitValue );
}
void TM1620B_W_CLK( uint8_t BitValue )
{
GPIO_WriteBit(TM1620B_PORT , TM1620B_CLK , (BitAction)BitValue );
}
void TM1620B_W_DIO( uint8_t BitValue )
{
GPIO_WriteBit(TM1620B_PORT , TM1620B_DIO , (BitAction)BitValue );
}
uint8_t TM1620B_R_DIO(void)
{
return GPIO_ReadInputDataBit(TM1620B_PORT , TM1620B_DIO );
}
/*****************************END:读写TM1620B管脚********************************************/
②发送一个字节
/*!
* @brief 发送一个数据字节
* @param Data
*/
void TM1620B_SendByte( uint8_t Data )
{
for (uint8_t i = 0; i < 8; i++)
{
TM1620B_W_DIO( Data & ( 0x01 << i ) ); //低位先行
TM1620B_W_CLK( 0 );
TM1620B_W_CLK( 1 ); //在时钟的上升沿操作
}
}
先改变数据位,后产生一个上升沿,低位先行。
(3)第GRID位显示数字Num
uint8_t Code_LedData[]={
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x77, //"A"
0x7C, //"B"
0x39, //"C"
0x5E, //"D"
0x79, //"E"
0x71, //"F"
0x76, //"H"
0x38, //"L"
0x37, //"n"
0x3E, //"u"
0x73, //"P"
0x5C, //"o"
0x40, //"-"
0x00 //熄灭
}; //7段共阴数码管编码
uint8_t TM1620B_GRID[] = { 0xC0,0xC2,0xC4,0xC6,0xC8,0xCA,0xCC }; //6位,第一位的共阴的地址
uint8_t TM1620B_SEG[2][24]; //用以区分7段数码管的低六段和高第七段,0:低六段 1:高第七段
TM1620B_GRID公共端GRID1~6的地址(SEG1~6的,SEG12的话地址加1),TM1620B_SEG用来分开段码(分为SEG1~6和SEG12)。
/*!
* @brief 第GRID位显示数字Num
* @param GRIDNum
* @param Num
*/
void TM1620B_ShowNum( uint8_t GRIDNum , uint8_t Num )
{
GRIDNum--;
for (uint8_t i = 0; i < 24; i++)
{
TM1620B_SEG[0][i] = Code_LedData[i] & 0x3F;
TM1620B_SEG[1][i] = (Code_LedData[i] & 0x40) >> 3 ;
}
for (uint8_t i = 0; i < 2; i++)
{
TM1620B_W_STB(0); //开始发数据
TM1620B_SendByte(0x02); //0000 0010 6位7段
TM1620B_W_STB(1);
TM1620B_W_STB(0);
TM1620B_SendByte(0x44); //0100 0(普通模式)1(固定地址)00(写数据到显示寄存器)
TM1620B_W_STB(1);
TM1620B_W_STB(0);
TM1620B_SendByte( TM1620B_GRID[GRIDNum] +i ); //i[0:低六段 1:高第七段]
TM1620B_SendByte( TM1620B_SEG[i][Num] );
TM1620B_W_STB(1);
TM1620B_W_STB(0);
TM1620B_SendByte(0x89); //1000 1(显示开)1XX(XX越大越亮)
TM1620B_W_STB(1);
}
}
按照固定地址模式去设置TM1620B的输出。
分两次显示,分别显示7段数码管的a~f和g。
(4)读按键
/*!
* @brief 读3个字节的按键信号
* @param
* @return
*/
uint32_t TM1620B_Read3Byte(void)
{
uint32_t Bytes = 0x0000 ;
TM1620B_W_DIO(1); //释放数据线
TM1620B_W_CLK(0);
for (uint8_t i = 0; i < 24; i++)
{
TM1620B_W_CLK(1);
if (TM1620B_R_DIO()==1)
{
Bytes = Bytes | ( 0x0001 << i ) ;
}
TM1620B_W_CLK(0);
}
TM1620B_W_CLK(1);
return Bytes;
}
返回3个字节的按键信号。
(5)在第GRID_Num([1:3])个数码管上显示数字Num(二位十进制数),同时可以读按键
/*!
* @brief 在第GRID_Num([1:3])个数码管上显示数字Num(二位十进制数)
* @param GRID_Num
* @param Num
* @return
*/
uint32_t TM1620B_ShowNumAndReadKey( uint8_t GRID_Num , uint8_t Num )
{
if (GRID_Num)
{
TM1620B_ShowNum(2*GRID_Num-1,Num/10);
TM1620B_ShowNum(2*GRID_Num,Num%10);
}
TM1620B_W_STB(0); //开始收按键数据
TM1620B_SendByte(0x42); //0100 0(普通模式)0(自动地址增加)10(读键扫数据)
uint32_t KeyBytes = TM1620B_Read3Byte();
TM1620B_W_STB(1);
return KeyBytes;
}
3、实物现象
/*****************数码管显示时间的程序 */
TaskHandle_t LED_Time_TaskHandler;
void LED_Time_Task( void *arg )
{
uint8_t LED_Num = 0;
while (1)
{
TM1620B_ShowNumAndReadKey(1,Time_Data[2]);
TM1620B_ShowNumAndReadKey(2,Time_Data[1]);
TM1620B_ShowNumAndReadKey(3,Time_Data[0]);
if (TM1620B_ShowNumAndReadKey(0,1) == 0x0002 )
{
//vTaskDelay(20);
if (TM1620B_ShowNumAndReadKey(0,1)== 0x0002)
{
while (TM1620B_ShowNumAndReadKey(0,1)== 0x0002)
{
}
LED_Num = (LED_Num+1)%20;
}
}
TM1616_ShowLed(LED_Num);
}
}
时钟芯片是RX8025T,分别在三组数码管上显示时分秒。
欢迎各位大佬批评指正。
另外板子是从嘉立创嫖的(感谢立创)。
作者:在海防吃馅饼的蟠桃