TM1628是一个带键盘扫描的LED驱动控制专用芯片,我正好有一块从旧点钞机上拆卸的TM1628控制板,板上除了TM1628芯片外,还有一个三位的数码管和三个微动按键(见下图),这段时间不能外出,正好就琢磨将其驱动起来。
下面是控制板的正面,一个三位数码管和三个独立的微动按键:
这是控制板的反面,一颗TM1628在正中央:
网上搜索到相关的资料后便开始编写代码,尝试将其点亮起来。首先根据器件的引脚和控制板上的连线,检查出三个按键分别接在KS1~KS3引脚上,数据管对应的引脚位置见下图,这些都是驱动编制程序的基本数据。
TM1628的控制主要有3个引脚,首先的STB,这个类似片选引脚,每当其从高低拉低后紧接着就是发出命令,之后可以进行读写操作,STB拉高后结束操作。其次是DIO,这是数据输入、输出引脚,串行输送,低位在前。然后是CLK,由主控设备给出时钟信号,时钟从高拉低时芯片准备输出数据(读取键盘数据时),时钟从低拉高时输入数据(主控设备应先准备好数据)。
然后就按照数据手册中的时序图和程序设计流程图来编写代码。TM1628有固定地址和自动地址两种方式,自动地址是每输入一个字节到芯片后,地址自动加一,我采用的是自动地址方式。
参照软件I2C的代码很快就完成了基本代码的编写,但在调试时却掉进了坑里,反复修改调试都不成功,时钟无论如何都无法调准,高电平维持时间不到1us,无论如何调整延时,延长的都是低电平时间,高电平时间纹丝不动,更换单片机的引脚也是同样结果。两天时间过去了,调试毫无进展,我以为可能是TM1628芯片损坏了准备放弃时,忽然想到不连接时钟引脚,单独测试单片机时发现时钟信号正常了由此确定还是TM1628控制板的问题。
连接了TM1628时的时序图:
时钟高电平时宽度不到1us:
不连接TM1628的CLK引脚时,单片机的时序正常:
时钟高低电平的宽度基本在5us左右:
通过仔细分析发现这块控制板上DIO引脚有上拉电阻,而CLK引脚却没有,目前的现象是时钟上拉后不能维持,我就尝试添加了一个上拉电阻,然后再测试,成功了,下面是成功之后的时序图:
下图是控制板上添加了时钟的上拉电阻:
这是数码管显示与LCD显示屏同步显示:
下面是驱动代码:
- #include "main.h"
- #include "tm1628.h"
- #include "lcd_5110.h"
- extern uint8_t buf[14],keys[3];
- const uint8_t dig[][2]=
- {
- 0x03,0xf0, //'0'
- 0x02,0x10, //'1'
- 0x02,0xe8, //'2'
- 0x02,0xb8, //'3'
- 0x03,0x18, //'4'
- 0x01,0xb8, //'5'
- 0x01,0xf8, //'6'
- 0x02,0x90, //'7'
- 0x03,0xf8, //'8'
- 0x03,0xb8, //'9'
- 0x03,0x38, //'Y'
- 0x03,0xd0, //'M'
- 0x02,0x78, //'D'
- 0x01,0x58, //'h'
- 0x00,0x58, //'m'
- 0x00,0x38, //'s'
- 0x00,0x08, //'-'
- 0x00,0x20, //'-'
-
-
- };
- void Delay_us(uint8_t s)
- {
- uint8_t i;
- for(i=0; i<s; i++);
- // for(j=0; j<10; j++);
- }
- /***************************************************
- *程 序 名:SI2C_Sda(uint8_t dir)
- *作 用:DAT引脚配置
- *输入参数:dir(0=输出,1=输入)
- *转出参数:无
- ***************************************************/
- void SI2C_Sda(uint8_t dir) //DAT端口配置(根据需要配置成输出或输入模式)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- if(dir == 0){
- GPIO_InitStruct.Pin = SI2C_SDA_Pin; //SDA输出模式、弱上拉
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(SI2C_SDA_GPIO_Port, &GPIO_InitStruct);
- }
- else{
- GPIO_InitStruct.Pin = SI2C_SDA_Pin; //SDA输入模式
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- HAL_GPIO_Init(SI2C_SDA_GPIO_Port, &GPIO_InitStruct);
- }
- HAL_GPIO_WritePin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin,GPIO_PIN_SET);
- }
- /******************************************************
- *程 序 名:TM6128_Init
- *作 用:初始化TM6128芯片引脚
- *输入参数:无
- *返回参数:无
- ******************************************************/
- void TM1628_Init(void)
- {
- //配置GPIO
- GPIO_InitTypeDef GPIO_InitStruct;
- GPIO_InitStruct.Pin = SI2C_SCL_Pin|SI2C_SDA_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- //设置引脚为高电平
- HAL_GPIO_WritePin(LED1_2_GPIO_Port,LED1_2_Pin,GPIO_PIN_SET);
- HAL_GPIO_WritePin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin,GPIO_PIN_SET);
- HAL_GPIO_WritePin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin,GPIO_PIN_SET);
-
- }
- /******************************************************
- *程 序 名:TM6128_Data(viod)
- *作 用:将Buf缓冲区14个字节写入TM6128芯片
- * 同时读5个字节的键盘数据到Buf
- *输入参数:无
- *返回参数:无
- ******************************************************/
- void TM1628_Data(void)
- {
- uint8_t i;
- SI2C_Sda(0); //设置DIO为输出
-
- STB_reset(); //拉低STB开始操作
- TM1628_Write(0x03); //设置显示模式(7位10段)
- STB_set(); //结束本命令
-
- STB_reset(); //拉低STB开始操作
- TM1628_Write(0x40); //设置写操作
- STB_set(); //结束本命令
-
- STB_reset(); //拉低STB开始操作
- TM1628_Write(0xc0); //地址从0开始
- Delay_us(1);
-
- for(i=0; i<14; i++){
- TM1628_Write(buf[i]);
- Delay_us(2); //Twait>2us
- }
- STB_set(); //拉高STB结束写操作
- Delay_us(4);
- STB_reset(); //拉低STB发出显示模式命令
- TM1628_Write(0x8c); //开显示,脉冲宽度11/16
- STB_set(); //拉高STB结束写操作
-
- STB_reset(); //拉低STB发出读键盘命令
- TM1628_Write(0x42); //
- SI2C_Sda(1); //设置sda为输入状态
- STB_reset(); //拉低STB开始读按键
- for(i=0; i<5; i++){
- buf[i] = TM1628_Read();
- }
- STB_set(); //拉高STB结束读操作
- //处理按键
- if(buf[0]&0x01)
- keys[0]++;
- if(buf[0]&0x08)
- keys[1]++;
- if(buf[1]&0x01)
- keys[2]++;
- LCD_write_value(0,3,3,0,1,keys[0]);
- LCD_write_value(30,3,3,0,1,keys[1]);
- LCD_write_value(60,3,3,0,1,keys[2]);
-
- }
- /******************************************************
- *程 序 名:TM6128_Read
- *作 用:TM6128芯片读1字节操作
- *输入参数:无
- *返回参数:读到的数据(1bety)
- ******************************************************/
- uint8_t TM1628_Read(void)
- {
- uint8_t dat,i;
- // CLK_reset(); //拉高CLK准备读数据
- for(i=0;i<8;i++){
- CLK_reset(); //拉低CLK
- Delay_us(1); //延时并准备数据
- dat>>=1;
- CLK_set(); //拉高CLK
- if(1 == HAL_GPIO_ReadPin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin))
- dat|=0x80;
- else
- __NOP();
- // Delay_us(1);
- }
- return dat;
- }
- /******************************************************
- *程 序 名:TM6128_Write
- *作 用:TM6128芯片写1字节操作
- *输入参数:要写入的数据(bety)
- *返回参数:无
- ******************************************************/
- void TM1628_Write(uint8_t dat)
- {
- uint8_t i;
-
- //开始写一字节数据(低位先)
- for(i=0;i<8;i++){
- CLK_reset(); //拉低CLK准备写数据
- if(dat&0x01)
- {
- DIO_set();
- }
- else
- {
- DIO_reset();
- }
- // Delay_us(1); //延时并准备数据
- CLK_set(); //拉高CLK
- __NOP();
- __NOP();
- __NOP();
- // Delay_us(1); //延时并准备数据
- dat = dat>>1;
- }
- }
- /******************************************************
- *程 序 名:Display_Digits(uint16_t value)
- *作 用:TM6128芯片显示变量(3位有效数字)
- *输入参数:要显示的变量(value)
- *返回参数:无
- ******************************************************/
- void Display_Digits(uint16_t value)
- {
- uint8_t n; //当前位值
-
- n = value / 100;
- buf[1] = dig[n][0];
- buf[0] = dig[n][1];
-
- n = value % 100 / 10;
- buf[3] = dig[n][0];
- buf[2] = dig[n][1];
-
- n = value % 10;
- buf[5] = dig[n][0];
- buf[4] = dig[n][1];
-
- TM1628_Data();
-
- }
复制代码
用杜邦线连接测试,不方便观察,所以就利用了旧摆件,将显示屏粘在松树上,核心板正好将马头遮住了,只好委屈它们了。
一周热门 更多>