关于STM32F051C8T6某项目总述
1. 总述目录
3. 模块总结(重点)
模块总结是对功能的解决方法进行总结,要实现单片机某种功能一定是软硬件配合,所以在叙述这段内容一定是先介绍硬件,再说明对应代码。
-
-
功能说明
TM1640是一款电子数码管驱动芯片,当我们需要驱动多个数码管时,就需要外部数码管驱动芯片进行控制。那么TM1640数码管驱动的详细过程是什么样的?在引脚分析中说明。
-
引脚分析
下面是对我们要用到的引脚进行分析,先上两个图:
由文档中引脚定义可知DIN和SCLK两个引脚分别是数据输入线和时钟线,根据时序图(如下)可知TM1640芯片数据传输遵守I2C协议(时钟线信号为低电平,数据线信号发生跳变,时钟线信号为高电平,数据线信号不可改变即有效),则DIN和SCLK代表I2C协议的数据线和时钟线。
SEG1-SEG8引脚文档中说此为段输出,何为段?在引脚图上看只能看出它是一个引脚,改引脚所代表的意义就需要看文档中的另一个图,如下:
从图中可看出SEG后面有一个字母(a~g,dp),而数码管的每一条灯管也有一个字母,那么SEG就代表一个一个灯管,具体0和1代表亮灭看电路连接。
那GRID1~GRID16引脚代表的是一整个数字的数码管,也就是一组数码管的开关控制。有引脚数量可得TM1640最多可支持16个数码管。
至此引脚分析完毕。
-
思路解析
那么TM1640是怎样对每个数码管进行启动的呢?地址和数据发送时序又是怎样的呢?
先来分析TM1640的指令格式:
指令分为数据指令、地址指令和控制指令三种。
数据指令是指TM1640将以怎样的方式加载数据,一共有两种方式,一种是地址自动加一(后文说),另一种是固定地址加载数据。这里所说的地址就是数码管地址(后文说),即地址指令,控制指令值数码管亮度和状态。TM1640在进行通信时首先要求主控要发送一个数据指令用来告诉TM1640用那种方式加载数据。其次要发送一个数码管地址作为数据加载的起始地址,然后根据如下图一和图二分析到底发送多少数据,最后再发送一个控制命令,这便是通讯时序思路。
接下来是三张图:
图一:
图二:
图三:
图一是固定地址时序,图二是写地址自动加一的时序,两者最大的区别在于数据的发送数量。数码管地址就是图三的显存地址。一个显存地址代表对一个数码管的操作。地址自动加一代表对起始地址之后的所有数码管操作。如果使用自动加一模式就需要传多个数据以I2C的end信号结束数据传输阶段。
-
代码解析
接下来是代码解析,首先是配置:
static I2C_Init_t TM1640_I2C_init = { .GPIO_Scl_Portx = GPIOB, .GPIO_Scl_Pinx = GPIO_Pin_3, .GPIO_Sda_Portx = GPIOA, .GPIO_Sda_Pinx = GPIO_Pin_15, .RCC_AHBPeriph_Scl_GPIOx = RCC_AHBPeriph_GPIOB, .RCC_AHBPeriph_Sda_GPIOx = RCC_AHBPeriph_GPIOA };
接着是初始化函数:
void I2C_OutputInit(I2C_Init_t *I2C_t) { GPIO_InitTypeDef GPIO_CFG; RCC_AHBPeriphClockCmd(I2C_t->RCC_AHBPeriph_Scl_GPIOx, ENABLE); RCC_AHBPeriphClockCmd(I2C_t->RCC_AHBPeriph_Sda_GPIOx, ENABLE); // 配置CLK和DATA引脚为输出模式 GPIO_CFG.GPIO_Pin = I2C_t->GPIO_Scl_Pinx | I2C_t->GPIO_Sda_Pinx; GPIO_CFG.GPIO_Mode = GPIO_Mode_OUT; GPIO_CFG.GPIO_OType = GPIO_OType_PP; GPIO_CFG.GPIO_PuPd = GPIO_PuPd_UP; GPIO_CFG.GPIO_Speed = GPIO_Speed_Level_3; GPIO_Init(I2C_t->GPIO_Scl_Portx, &GPIO_CFG); GPIO_Init(I2C_t->GPIO_Sda_Portx, &GPIO_CFG); }
然后是头文件指令格式:
// Data Cmd #define ADDR_INCR (0x40) #define ADDR_SET (0x41) // Display Contrl Cmd #define DISPLAY_CMD (0x88) // Addr Cmd #define ADDR_CMD (0xC0) #define ADDR_WORK_LED (0xC6) // 亮度 #define ON_1_16 (DISPLAY_CMD + 0) #define ON_2_16 (DISPLAY_CMD + 1) #define ON_4_16 (DISPLAY_CMD + 2) #define ON_10_16 (DISPLAY_CMD + 3) #define ON_11_16 (DISPLAY_CMD + 4) #define ON_12_16 (DISPLAY_CMD + 5) #define ON_13_16 (DISPLAY_CMD + 6) #define ON_14_16 (DISPLAY_CMD + 7) #define OFF (0x80) union EightSegmentCode { uint8_t uint8_LED; struct { unsigned char A : 1; unsigned char B : 1; unsigned char C : 1; unsigned char D : 1; unsigned char E : 1; unsigned char F : 1; unsigned char G : 1; unsigned char DP : 1; } Bits; struct { uint8_t ABCDEFG : 7; uint8_t DP : 1; } Bits1; };
下面是设置两种加载模式:
void TM1640_SetAddrINC_Mode(void) { I2C_Start(&TM1640_I2C_init); TM1640_SendByte(ADDR_INCR); I2C_Stop(&TM1640_I2C_init); } void TM1640_SetAddrSET_Mode(void) { I2C_Start(&TM1640_I2C_init); TM1640_SendByte(ADDR_SET); I2C_Stop(&TM1640_I2C_init); }
下面是分别用两种方式发送数据实现:
void TM1640_Display(uint8_t addr, uint8_t data) { TM1640_SetAddrSET_Mode(); I2C_Start(&TM1640_I2C_init); TM1640_SendByte(addr); TM1640_SendByte(data); I2C_Stop(&TM1640_I2C_init); TM1640_SetBrightNess(ON_14_16); } void TM1640_Display_all(uint8_t *data) { uint8_t i; I2C_Start(&TM1640_I2C_init); TM1640_SendByte(ADDR_CMD); for (i = 0; i < 16; i++) { TM1640_SendByte(*data); data++; } I2C_Stop(&TM1640_I2C_init); TM1640_SetBrightNess(ON_14_16); }
下面是打开自动加一模式全部灯光和关闭全部灯光:
void TM1640_All_ON(void) { uint8_t i; for (i = 0; i < 16; i++) { TM1640_InitCode[i].uint8_LED = 0xFF; } TM1640_SetAddrINC_Mode(); TM1640_Display_all((uint8_t*)TM1640_InitCode); TM1640_SetBrightNess(ON_14_16); } void TM1640_All_OFF(void) { uint8_t i; for (i = 0; i < 16; i++) { TM1640_InitCode[i].uint8_LED = 0x00; } TM1640_SetAddrINC_Mode(); TM1640_Display_all((uint8_t*)TM1640_InitCode); }
下面是操作固定模式下的数码管:
void TM1640_Work_Led_ON(void) { TM1640_Display(ADDR_WORK_LED, TM1640_ADDR_WORKE_ON); }
由于工作要求不能发完整工程。以上是对TM1640的使用总结
-
-
…
自行转载即可,转载请注明出处
内容代表个人感悟,不保证正确性