本帖最后由 qjp1988113 于 2020-10-10 10:43 编辑
最近一个项目用到TM1628模块控制数码管,手头上正好有TM1638这个模块。
比较了TM628和TM1638,发现除了后者寄存器多一组外,其他操作几乎一致,可以验证。
就用STM32G431 NUCLEO试了一下,也不能浪费它啊,毕竟它是ST最近的主推呢。
外设配置直接用STM32CUBEMX配置,简单省事,这也是ST生态软件
做的好的缘故,让人有欲望用。
控制TM138用模拟的IO来实现的。TM1638是国产的芯片,数据手册
全中文,阅读很方便,唯一的一个坑就是这货需要一定的初始化时间,
我之前给的时间不够,就不能正确控制。
CUBEMX仅定义3个IO口:
TM1368的基本读写操作时序(主意:最小延时间隔1us):
TM1368的自增1地址操作的时序:
TM1368的固定地址操作的时序:
TM1368读操作时序:
具体c及头文件h:
#include "tm1628.h"
uint8_t SMG_Value[6]={0,0,0,0,0,0};//6个数码管
//共阴数码管显示代码 1~10 A B C D E F
//仅占用数码管的1~7位 其余8,9,10,12
const uint8_t Numtab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
/***************************************************
*程 序 名:Tm1628_DATA_PINDIR(uint8_t dir)
*作 用:DAT引脚配置
*输入参数:dir(0=输出,1=输入) 默认状态下为输出
*转出参数:无
***************************************************/
void Tm1628_DATA_PINDIR(uint8_t dir) //DAT端口配置(根据需要配置成输出或输入模式)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(dir == 0)
{
GPIO_InitStruct.Pin = TM1638_DIO_Pin; //SDA输出模式、弱上拉
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(TM1638_DIO_GPIO_Port, &GPIO_InitStruct);
}
else
{
GPIO_InitStruct.Pin = TM1638_DIO_Pin; //SDA输入模式
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(TM1638_DIO_GPIO_Port, &GPIO_InitStruct);
}
HAL_GPIO_WritePin(TM1638_DIO_GPIO_Port,TM1638_DIO_Pin,GPIO_PIN_SET);
}
/*************************************
函数名称:Tm1628_Write_Byte
函数说明:写单个字节
函数参数:命令参数
函数返回:NULL
*************************************/
void Tm1628_Write_Byte(uint8_t data)
{
uint8_t i;
Tm1628_CKL_H;
Tm1628_DIO_H;
for(i = 0; i < 8; i++)
{
Tm1628_CKL_L;
delay_us(10);
if((data & 0x01) == 1)
Tm1628_DIO_H;
else
Tm1628_DIO_L;
data = data >> 1;
Tm1628_CKL_H;
delay_us(10);
}
}
/*************************************
函数名称:Tm1628_Read_Byte
函数说明:读单个字节 Tm1628_DIO_Value
函数参数:命令参数
函数返回:NULL
*************************************/
uint8_t Tm1628_Read_Byte(void) //读数据函数
{
uint8_t i;
uint8_t temp=0;
Tm1628_DATA_PINDIR(1); //设置为输入
delay_us(10);
for(i=0;i<8;i++)
{
temp>>=1;
Tm1628_CKL_L;
delay_us(10);
if(Tm1628_DIO_Value)
temp|=0x80;
Tm1628_CKL_H;
delay_us(10);
}
Tm1628_DATA_PINDIR(0); //设置为输出
delay_us(10);
return temp;
}
/*************************************
函数名称:Tm1628_Write_Command
函数说明:写命令
函数参数:命令参数
函数返回:NULL
*************************************/
void Tm1628_Write_Command(uint8_t cmd)
{
Tm1628_STB_L;
delay_us(10);
Tm1628_Write_Byte(cmd);
Tm1628_STB_H;
delay_us(10);
}
/*************************************
函数名称:Tm1628_Write_Command
函数说明:写命令
函数参数:命令参数
函数返回:NULL
*************************************/
uint8_t Tm1628_Read_key(void)
{
uint8_t c[4],i,key_value=0;
Tm1628_STB_L;
delay_us(10);
Tm1628_Write_Byte(0x42); //读键扫数据 命令
for(i=0;i<4;i++)
c=Tm1628_Read_Byte();
Tm1628_STB_H;
delay_us(10); //4个字节数据合成一个字节
for(i=0;i<4;i++)
key_value|=c<<i;
for(i=0;i<8;i++)
if((0x01<<i)==key_value)
break;
return i;
}
/*************************************
函数名称:Tm1628init
函数说明:TM1628初始化
函数参数:NULL
函数返回:NULL
*************************************/
void Tm1628init(void)
{
uint8_t InitData[14]={Numtab[0],Numtab[0],Numtab[0],Numtab[0],Numtab[0],
Numtab[0],Numtab[0],Numtab[0],Numtab[0],Numtab[0],Numtab[0],Numtab[0],Numtab[0],Numtab[0]};
//Tm1628_Write_Command(0x03); //7位10段
//Tm1628_Write_Command(MODE_COMMAND|MODE_6W11D); //6位11段
Tm1628_Write_Command(MODE_COMMAND|MODE_7W10D); //7位10段
Tm1628_ClearDisplay(); //清屏
Tm1628_GrayScale(8); //亮度2
//Tm1628_Fixed(0xc2,0XFF);
//初始化每个显示0
Tm1628_Continuous(0XC0, 14, InitData);
}
/*************************************
函数名称:Tm1628_Fixed
函数说明:固定写显示
函数参数:(1)data 地址
(2)add 数据
函数返回:NULL
*************************************/
void Tm1628_Fixed(uint8_t add, uint8_t data)
{
Tm1628_Write_Command(0x44);
Tm1628_STB_L;
delay_us(10);
Tm1628_Write_Byte(add);
Tm1628_Write_Byte(data);
Tm1628_STB_H;
delay_us(10);
}
/*************************************
函数名称:Tm1628_Continuous
函数说明:连续写显示
函数参数:(1)data 地址 从C0开始
(2)num 数据
(3)add 数量 最大14
函数返回:NULL
*************************************/
void Tm1628_Continuous(uint8_t add, uint8_t num, uint8_t *data)
{
uint8_t i;
Tm1628_Write_Command(0x40);
Tm1628_STB_L;
delay_ms(1);
Tm1628_Write_Byte(add);
for(i = 0; i < num; i++)
{
Tm1628_Write_Byte(data);
}
Tm1628_STB_H;
delay_ms(1);
}
/*************************************
函数名称:Tm1628_ClearDisplay
函数说明:清屏
函数参数:NULL
函数返回:NULL
*************************************/
void Tm1628_ClearDisplay(void)
{
uint8_t i;
Tm1628_Write_Command(0x40);
Tm1628_STB_L;
delay_ms(1);
Tm1628_Write_Byte(0xC0);
for(i = 0; i < 14; i++)
{
Tm1628_Write_Byte(0x00);
}
Tm1628_STB_H;
delay_ms(1);
}
/*************************************
函数名称:Tm1628_GrayScale
函数说明:用于亮度调节 0 - 9
函数参数:亮度 0 - 9
函数返回:NULL
*************************************/
void Tm1628_GrayScale(uint8_t data)
{
switch(data)
{
case(0): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_OFF);break;//关闭
case(1): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale1); break;
case(2): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale2); break;
case(3): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale3); break;
case(4): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale4); break;
case(5): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale5); break;
case(6): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale6); break;
case(7): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale7); break;
case(8): Tm1628_Write_Command(DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale8); break;
}
}
//由于使用了1~10 12 超出了8位 每次写一个数码管数据 需占用2个字节 2个地址
//固定地址写 其实地址只能是 0XC0 0XC2 0XC4 0XC6 0XC8 0XCA 0XCC
//函数参数:(1)data 地址 从C0开始
//(2)num 数据
//(3)add 数量 最大14
void Tm1628_WriteOneSMG(uint8_t add, uint16_t data)
{
uint8_t tmp[2];
tmp[0]=data&0xFF;//低8位
tmp[1]=data>>8;//高8位
Tm1628_Continuous(add,2,tmp);
}
void Tm1628_Write_allLED(unsigned char LED_flag) //控制全部LED函数,LED_flag表示各个LED状态
{
unsigned char i;
for(i=0;i<8;i++)
{
if(LED_flag&(1<<i))
//Write_DATA(2*i+1,3);
Tm1628_Fixed(0xc0|(2*i)+1,1);
else
Tm1628_Fixed(0xc0|(2*i+1),0);
}
}
//////////////////////////////////////////
#ifndef __TM1628_H #define __TM1628_H
#include "main.h"
#include "delay.h"
//控制引脚定义
#define Tm1628_CKL_H HAL_GPIO_WritePin(TM1638_CLK_GPIO_Port,TM1638_CLK_Pin,GPIO_PIN_SET)
#define Tm1628_CKL_L HAL_GPIO_WritePin(TM1638_CLK_GPIO_Port,TM1638_CLK_Pin,GPIO_PIN_RESET)
#define Tm1628_DIO_H HAL_GPIO_WritePin(TM1638_DIO_GPIO_Port,TM1638_DIO_Pin,GPIO_PIN_SET)
#define Tm1628_DIO_L HAL_GPIO_WritePin(TM1638_DIO_GPIO_Port,TM1638_DIO_Pin,GPIO_PIN_RESET)
#define Tm1628_STB_H HAL_GPIO_WritePin(TM1638_STB_GPIO_Port, TM1638_STB_Pin,GPIO_PIN_SET)
#define Tm1628_STB_L HAL_GPIO_WritePin(TM1638_STB_GPIO_Port, TM1638_STB_Pin,GPIO_PIN_RESET)
#define Tm1628_DIO_Value HAL_GPIO_ReadPin(TM1638_DIO_GPIO_Port,TM1638_DIO_Pin)
//指令定义 B7 B6 区别不同的指令
// B7 B6 指令
// 0 0 显示模式命令设置
// 0 1 数据命令设置
// 1 0 显示控制命令设置
// 1 1 地址命令设置
#define MODE_COMMAND 0X00 //显示模式
#define DATA_COMMAND 0X40 //数据
#define DISP_COMMAND 0x80 //显示控制指令
#define ADDR_COMMAND 0XC0 //地址
//显示模式 B1 B0
#define MODE_4W13D 0x00 //4位13段
#define MODE_5W12D 0x01 //5位12段
#define MODE_6W11D 0x02 //6位11段
#define MODE_7W10D 0x03 //7位10段
//真正调用某指令 如6位11段 MODE_COMMAND|MODE_6W11D 即可
//数据 B3 B2 B1 B0
#define DATA_WRITEMODE 0X00 //写数据到显示寄存器
#define DATA_READMODE 0X02 //读按键扫描数据
#define DATA_AUTOADDADDRESS 0X00 //地址自动加1模式
#define DATA_FIXADDRESS 0X04 //固定地址模式
//例:设置写数据 固定地址 DATA_COMMAND|DATA_WRITEMODE|DATA_FIXADDRESS
//显示控制 B3 B2 B1 B0 共8级辉度可调
#define DISP_GrayScale_OFF 0x00 //关显示
#define DISP_GrayScale_ON 0x08 //开显示
#define DISP_GrayScale1 0x00 //灰度等级1
#define DISP_GrayScale2 0x01 //灰度等级2
#define DISP_GrayScale3 0x02 //灰度等级3
#define DISP_GrayScale4 0x03 //灰度等级4
#define DISP_GrayScale5 0x04 //灰度等级5
#define DISP_GrayScale6 0x05 //灰度等级6
#define DISP_GrayScale7 0x06 //灰度等级7
#define DISP_GrayScale8 0x07 //灰度等级8
//例:设置开显示 辉度2 DISP_COMMAND|DISP_GrayScale_ON|DISP_GrayScale2
//地址 B3 B2 B1 B0 。最多有效地址为14位(C0H-CDH),如果地址设为CEH或更高,数据被忽
//略,直到有效地址被设定。上电时,地址默认设为C0H。
#define ADDR_SFR_00H 0X00
#define ADDR_SFR_01H 0X01
#define ADDR_SFR_02H 0X02
#define ADDR_SFR_03H 0X03
#define ADDR_SFR_04H 0X04
#define ADDR_SFR_05H 0X05
#define ADDR_SFR_06H 0X06
#define ADDR_SFR_07H 0X07
#define ADDR_SFR_08H 0X08
#define ADDR_SFR_09H 0X09
#define ADDR_SFR_0AH 0X0A
#define ADDR_SFR_0BH 0X0B
#define ADDR_SFR_0CH 0X0C
#define ADDR_SFR_0DH 0X0D
//例:设置地址0x01有效 ADDR_COMMAND|ADDR_SFR_01H
#define SMG1_ADDR ADDR_COMMAND|ADDR_SFR_00H
#define SMG2_ADDR ADDR_COMMAND|ADDR_SFR_02H
#define SMG3_ADDR ADDR_COMMAND|ADDR_SFR_04H
#define SMG4_ADDR ADDR_COMMAND|ADDR_SFR_06H
#define SMG5_ADDR ADDR_COMMAND|ADDR_SFR_08H
#define SMG6_ADDR ADDR_COMMAND|ADDR_SFR_0AH
#define SMG7_ADDR ADDR_COMMAND|ADDR_SFR_0CH
extern const uint8_t Numtab[];
void Tm1628init(void); //TM1628初始化
void Tm1628_DATA_PINDIR(uint8_t dir);
uint8_t Tm1628_Read_key(void);
void Tm1628_Fixed(uint8_t add, uint8_t data); //固定写显示 data 地址 add 数据
void Tm1628_Continuous(uint8_t add, uint8_t num, uint8_t *data); //连续写显示
void Tm1628_ClearDisplay(void); //清屏
void Tm1628_GrayScale(uint8_t data); //亮度调节
void Tm1628_WriteOneSMG(uint8_t add, uint16_t data);
void Tm1628_Write_allLED(unsigned char LED_flag);
#endif
main函数调用,初始化加测试显示:uint8_t num[8]; //各个数码管显示的值
uint8_t test1Num[14]={Numtab[0],0,Numtab[1],0,Numtab[2],0,Numtab[3],0,
Numtab[4],0,Numtab[5],0,Numtab[6]};
//tm1628.h 里面的函数控制 --PASS
Tm1628init();
delay_ms(2000);
Tm1628_WriteOneSMG(SMG1_ADDR,Numtab[2]);//写一个数码管
delay_ms(2000);
Tm1628_Fixed(SMG2_ADDR,Numtab[2]);//固定地址写
delay_ms(2000);
Tm1628_Continuous(0XC0, 14, test1Num);//连续地址写
delay_ms(2000);
Tm1628_ClearDisplay(); //清屏
delay_ms(2000);
while(1)
{
i=Tm1628_Read_key();
if(i<8)
{
num++;
while(Tm1628_Read_key()==i); //等待按键释放
if(num>15)
num=0;
Tm1628_Fixed(0XC0|(i*2),Numtab[num]);
Tm1628_Write_allLED(1<<i);
}
}
编译,下载,观察现象:
|
共1人点赞
|