目前市面上有一些數碼管顯示芯片,其中TM1637是比較經典,也是我個人比較喜歡的一款芯片。TM1637是天微電子的一款帶按鍵掃描的8段*6位數碼管驅動芯片,本次使用STM32F103C8T6驅動四位數碼管。(下圖:TM1637功能及管腳,來源TM1637開發手冊)

I2C驅動:
TM1637采用的通信方式是I2C通信,所以我們首先來簡單介紹下I2C的通信方式:
I2C通信是一種經典的通信協議,在物理層上,它使用SDA(串行數據線),SCL(串行時鍾線)兩條線控制一個或多個設備。既然通過一條數據線控制多個設備,那么設備就必定有一個獨屬於自己的地址(類似於ID),以便於主機可以和不同的設備通信。
在協議層上,I2C通信時會首先發送一個Start信號,這時,在數據線上的設備都會聽到這個信號,並等待着下一個信號:地址信號的到來。主機在開始信號后會發送地址信號,如果這個地址不是從機設備的地址,那么這個從機會忽略后面的消息,因為主機的通信對象不是它,它不需要繼續聽下去(這也不太禮貌)。但如果這個地址是從機的地址,那么從機會發送一個應答信號,表示”我聽到了“。
由於本次是我們是單方面向TM1637寫數據,所以I2C中主機由從機中讀數據不再贅述。接下來主機會發送多個字節的數據,主機每發送一個字節的數據,從機就會應答一次,當主機想要停止發送,就會發送一個停止數據,整個通信流程就完成了。(圖源網絡,地址位也可能是10位)

TM1637驅動代碼:
知道了通信方式,我們就可以比較輕松的編寫出TM1637的驅動代碼,先看看官方給出的程序流程:

這里我們舍去按鍵掃描的程序,直接使用I2C驅動,並使用圖中的地址自加模式
我們先進行頭文件中宏的定義:
#ifndef __TM1637_H #define __TM1637_H #include "stm32f10x.h" #include "sys.h" //與庫函數操作取一個 #define SDA_IN() {GPIOA->CRL&=0X0FFFFFFF;GPIOA->CRL|=(u32)8<<28;} //通過寄存器更改為輸入 #define SDA_OUT() {GPIOA->CRL&=0X0FFFFFFF;GPIOA->CRL|=(u32)3<<28;} //通過寄存器更改為輸出 #define TM_SCL_PORT GPIOA #define TM_SCL_CLK RCC_APB2Periph_GPIOA #define TM_SCL_PIN GPIO_Pin_5 #define TM_DIO_PORT GPIOA #define TM_DIO_CLK RCC_APB2Periph_GPIOA #define TM_DIO_PIN GPIO_Pin_7
#define TM_SCL PAout(5)
#define TM_SDA PAout(7)
#define READ_SDA PAin(7)
/*函數聲明,這里省略,使用時請自加*/
#endif
在驅動文件TM1637.c中首先是I2C初始化,這里使用了軟件I2C
#include "TM1637.h" #include "delay.h" void TM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(TM_DIO_CLK|TM_SCL_CLK,ENABLE); GPIO_InitStructure.GPIO_Pin = TM_DIO_PIN | TM_SCL_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(TM_DIO_PORT,&GPIO_InitStructure); // TM_SCL=1; // TM_SDA=1; }
然后是開始,停止,等待應答,寫一個8位數據的函數
void TM_Start(void) { TM_SDA=1; delay_us(2); TM_SCL=1; delay_us(2); TM_SDA=0; delay_us(2); TM_SCL=0; delay_us(2); } void TM_Stop(void) { TM_SCL=0; delay_us(2); TM_SDA=0; delay_us(2); TM_SCL=1; delay_us(2); TM_SDA=1; delay_us(2); } void TM_Wait_Ask(void) { SDA_IN(); unsigned char i; TM_SCL=0; delay_us(5); while(READ_SDA==1&&(i<250))i++; TM_SCL=1; delay_us(2); TM_SCL=0; SDA_OUT(); } void TM_WriteByte(uint8_t txd) { uint8_t i; for(i=0;i<8;i++) { TM_SCL=0; delay_us(2); if(txd & 0x01){ TM_SDA=1; } else { TM_SDA=0; } delay_us(3); txd>>=1; TM_SCL=1; delay_us(3); } //TM_Wait_Ask(); }
最后是main中使用的Display函數,這里的函數適用於4位數碼管:
void TM_Display(uint8_t *discode) { uint8_t i; TM_Start(); TM_WriteByte(0x40); //40 地址自加模式 44 固定地址模式 TM_Wait_Ask(); TM_Stop(); TM_Start(); TM_WriteByte(0xc0); //首地址 TM_Wait_Ask(); for(i=0;i<4;i++) { TM_WriteByte(*(discode+i)); //依次發送數組數據 TM_Wait_Ask(); } TM_Stop(); TM_Start(); TM_WriteByte(0x89); //亮度 TM_Wait_Ask(); TM_Stop(); }
在主函數中,我們需要定義一個字符數組,以顯示正確的字符,同時需要定義一個uint8_t長度的四位數組,即可進行顯示。
unsigned char Data[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //不帶點 unsigned char DataD[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; //帶點 uint8_t time[4]={0x3f,0x3f,0x3f,0x3f}; //一個四位數組,這里代表0000 TM_Display(time); //進行顯示!
以上就是STM32通過I2C驅動TM1637的相關內容。
代碼有幾處借鑒了網上或者TM官方的思路,文章純手打,如果轉載使用望注明一下博客地址。 |・ω・)
