利用TM1650控制鍵盤操作
阿新 • • 發佈:2020-10-23
1. TM1650簡介
TM1650是深圳市天微電子股份有限公司系列數碼管驅動晶片的一個型號,在驅動數碼管的同時,可以控制鍵盤操作,資料手冊下載。
- 驅動8段4位共陰數碼管
- 工作電壓3-5V
- 驅動7×4=28個按鍵
2. 特點
- 價格比較便宜:淘寶上大約0.2元/個左右,加上外圍電阻、電容,大概總共0.5元
- 佔用I/O資源少:資料線(第3腳SDA)、時鐘線(第2腳SCL)各一條
- 有按鍵後,第16腳DP會提供低電平,可用作微控制器的外部中斷,這樣可省去微控制器輪詢按鍵的動作(7段開屏時)
3. 原理圖
- CN2連線鍵盤,適用於最多4×4的鍵盤
- DIG1~DIG4分別連線鍵盤的4行
- A~G分別連線鍵盤的7列,圖中只用到4列,因此E、F、G未連線
- MCU使用的是STC8G1K08-20PIN的
- sbit KEY_KEY_SCL = P1^7
- sbit KEY_KEY_SDA = P1^6
- sbit KEY_IRQ = P3^7
4. 根據時序圖寫出基本操作指令
4.1 START
1 /******************************************************** 2 *說明:TM1650的START動作 3 *備註:start之後,CLK和SDA均處於0狀態 4 *TM1650時序圖:CLK時鐘週期最小為200ns,相當於頻率為:1s/200ns=5MHz, 5 *手冊中描述了平均傳輸速率為4MHz,對應週期為1s/4Mhz=250ns6 *同時,根據上位機和硬體介面的配置,平均傳輸速率會出現較大差異,建議值為100kHz(0.1Mhz)以下 7 *100kHz的頻率對應週期為:1s/100k=10us 8 *STC8g設定的主頻為22.1184MHz,週期為1s/22.1184MHz=45.2ns 9 *使用_nop_()實現延時已遠遠不能滿足要求,看網上的例子不少都是延時5us,這裡也採用一下 10 *********************************************************/ 11 void start(void) 12 { 13 KEY_SCL = 1; 14 KEY_SDA = 1; 15 Delay1us(5); 16 KEY_SDA = 0; 17 Delay1us(5); 18 KEY_SCL = 0; 19 Delay1us(5); 20 }
4.2 ACT
1 /******************************************************** 2 *說明:TM1650的ACT動作 3 *備註:如果本次通訊正常,晶片在序列通訊的第8個時鐘下降沿後, 4 * TM1650主動把DAT拉低------因此DAT拉低是TM1650的硬體行為 5 * 直到檢測到CLK來了上升沿,DAT釋放為輸入狀態(本晶片) 6 * act結束後,CLK和DAT線均處於低電平狀態 7 *********************************************************/ 8 void act(void) 9 { 10 unsigned char i; 11 i = 0; 12 while(KEY_SDA && (i < 100)) 13 { 14 i++; 15 } 16 KEY_SCL = 1; 17 Delay1us(5); 18 KEY_SCL = 0; 19 Delay1us(5); 20 }
4.3 STOP
/******************************************************** *說明:TM1650的stop動作 *備註:stop後兩條線均處於高電平狀態 *********************************************************/ void stop(void) { KEY_SCL=1; Delay1us(5); KEY_SDA=1; Delay1us(5); }
4.4 WRITE
1 /*************************************************** 2 *說明:操作TM1650的底層寫函式 3 *引數:byte為寫入TM1650的位元組 4 *備註:io.h中定義了控制TM1650晶片的兩個管腳 5 * sbit KEY_SCL = P1^7; 6 * sbit KEY_SDA = P1^6; 7 *在wrt之前的start動作已經置CLK和SDA與低電平狀態 8 ***************************************************/ 9 void wrt(unsigned char byte) 10 { 11 unsigned char i; 12 for(i = 8; i > 0; i--) 13 { 14 byte <<= 1; //高位在前 15 if(CY) 16 { 17 KEY_SDA = 1; 18 } 19 else 20 { 21 KEY_SDA = 0; 22 } 23 Delay1us(5); 24 KEY_SCL = 1; 25 Delay1us(5); 26 KEY_SCL = 0; 27 Delay1us(5); 28 } 29 // 寫完8bit後CLK處於低電平狀態 30 }
4.5 READ
1 /*************************************************** 2 *說明:操作TM1650的底層讀函式 3 *返回:讀取按鍵的TM1650程式碼 4 *備註:io.h中定義了控制TM1650晶片的兩個管腳 5 * sbit KEY_SCL = P1^7; 6 * sbit KEY_SDA = P1^6; 7 *指令順序:start-command(4f)-ack-讀key-ack-stop 8 ***************************************************/ 9 unsigned char read(void) 10 { 11 unsigned char i; 12 unsigned char coder = 0; 13 start(); 14 wrt(COMMAND_READ_KEY_DATA); //讀按鍵命令 15 act(); 16 for(i = 8; i > 0; i--) 17 { 18 KEY_SCL = 1; 19 Delay1us(5); 20 coder <<= 1; 21 if(KEY_SDA) 22 { 23 coder++; 24 } 25 KEY_SCL = 0; 26 Delay1us(5); 27 } 28 act(); 29 stop(); 30 return coder; 31 }
4.6 使用的一些巨集
1 //命令巨集定義區---------------------------開始*/ 2 #define COMMAND_SET_PARAMETER 0x48 //設定系統引數命令 3 #define COMMAND_READ_KEY_DATA 0x49 //讀取按鍵資料命令 4 //命令巨集定義區---------------------------結束*/ 5 6 //引數巨集定義區---------------------------開始*/ 7 #define PARAMETER_BRIGHTNESS_NORMAL 0x00 8 #define PARAMETER_BRIGHTNESS_ONE 0x10 9 #define PARAMETER_BRIGHTNESS_TWO 0x20 10 #define PARAMETER_BRIGHTNESS_THREE 0x30 11 #define PARAMETER_BRIGHTNESS_FOUR 0x40 12 #define PARAMETER_BRIGHTNESS_FIVE 0x60 13 #define PARAMETER_BRIGHTNESS_SIX 0x60 14 #define PARAMETER_BRIGHTNESS_SEVEN 0x70 15 16 #define PARAMETER_SEGMENT_MODE_EIGHT 0x00 //8段輸出(預設) 17 #define PARAMETER_SEGMENT_MODE_SEVEN 0x08 //7段輸出,用於鍵盤讀出時,16腳DP/KP為鍵盤掃描標識輸出 18 // 7段模式且開屏時(48H+09H): 19 // 在沒有按鍵按下時DP/KP腳輸出高電平 20 // 在有按鍵按下時,DP/KP腳會輸出低電平 21 // 當下一次按鍵資料被讀取後(或關屏)DP/KP腳輸出高電平 22 // KP可以用作是否有按鍵的指示,連線MCU的外部中斷腳 23 #define PARAMETER_WORK_MODE_RUNNING 0x00 //正常工作模式 24 #define PARAMETER_WORK_MODE_STANDBY 0x04 //待機工作模式 25 26 #define PARAMETER_DISPLAY_MODE_OFF 0x00 //關閉屏顯示 27 #define PARAMETER_DISPLAY_MODE_ON 0x01 //開啟屏顯示 28 // 當傳送開屏命令且為正常工作模式時,DIG1-DIG4開始進行掃描 29 // 所以,讀鍵盤時也需要開屏 30 //引數巨集定義區---------------------------結束*/
5 TM1650的初始化
1 /*************************************************** 2 *說明:初始化連線鍵盤晶片的管腳 3 *備註:io.h中定義了控制TM1650晶片的三個管腳 4 * sbit KEY_KEY_SCL = P1^7; 5 * sbit KEY_KEY_SDA = P1^6; 6 * sbit KEY_IRQ = P3^7; 在7段模式下,在沒有按鍵按下時DP/KP腳輸出高電平, 7 * 在有按鍵按下時, DP/KP腳會輸出低電平, 8 * 當下一次按鍵資料被讀取後(或關屏) DP/KP腳輸出高電平 9 * (讀按鍵時資料從TM1650輸出到MCU,此時與TM1650的DAT相連的IO口必須設定為輸入模式且釋放匯流排) 10 * 將這兩個管腳設定成準雙向模式(00) 11 *操作順序:start-command1(系統命令)-act-command2(系統引數設定)-act-stop 12 ***************************************************/ 13 void TM1650_Init(void) 14 { 15 // 留出上電初始化時間 16 Delay1ms(60); 17 // 設定兩線管腳工作模式,準雙向(00) 18 P1M1 &= ~(0x03<<6); 19 P1M0 &= ~(0x03<<6); 20 // 讀鍵盤功能初始化,7段、正常模式、開屏 21 start(); 22 wrt(COMMAND_SET_PARAMETER); 23 act(); 24 wrt(PARAMETER_SEGMENT_MODE_SEVEN | PARAMETER_WORK_MODE_RUNNING | PARAMETER_DISPLAY_MODE_ON); 25 act(); 26 stop(); 27 //KEY_IRQ P3.7初始化為INT3 28 INTCLKO |= 1<<5; // 允許INT3(僅支援下降沿中斷) 29 EA = 1; 30 // TM1650第16腳DP按鍵觸發訊號引腳初始化,高阻模式(預設值) 31 P3M1 |= 0x01 << 7; // 1 32 P3M0 &= ~(0x01 << 7); // 0 33 }
6. 鍵盤中斷處理
1 /************************************************** 2 *說明:按下某個按鍵時觸發INT3中斷,這是INT3的中斷處理程式 3 **************************************************/ 4 void Int3_Irq(void) interrupt 11 5 { 6 g_FlagKeyPressed = TRUE; 7 }
g_FlagKeyPressed是一個全域性變數,main函式中只需要檢視該變數的值就知道是否有按鍵被按下了。
7. 按鍵的讀取
通過外部中斷得到有按鍵被按下的訊息後,就可讀取按鍵值了。下面程式中巨集ZERO代表0的ASCII碼0x30,其他類同。
1 /*************************************************** 2 *說明:讀取按鍵的值 3 *返回:根據自己的鍵盤佈局,將得到的值與所按鍵的ASCII碼進行對應 4 ***************************************************/ 5 unsigned char TM1650_GetKeyAscii(void) 6 { 7 unsigned char key; 8 do{ 9 key = read(); 10 }while(key > 0x40); // 等待按鍵鬆開 11 init(); // 初始化TM1650 12 13 //BeepBlink(); //聲光提示(其他功能,與操作TM1650無關) 14 15 switch(key) 16 { 17 case 0x0f: 18 return ZERO; 19 break; 20 case 0x17: 21 return HASH; 22 break; 23 case 0x07: 24 return ASTERISK; 25 break; 26 case 0x0e: 27 return EIGHT; 28 break; 29 case 0x16: 30 return NINE; 31 break; 32 case 0x06: 33 return SEVEN; 34 break; 35 case 0x0d: 36 return FIVE; 37 break; 38 case 0x15: 39 return SIX; 40 break; 41 case 0x05: 42 return FOUR; 43 break; 44 case 0x0c: 45 return TWO; 46 break; 47 case 0x14: 48 return THREE; 49 break; 50 case 0x04: 51 return ONE; 52 break; 53 default: 54 return 0; 55 } 56 }
上段程式中,第11行init()非常重要,其作用是再次初始化TM1650。具體原因如下:
1)當某個按鍵被按下時,DP給出低電平,觸發外部中斷,進而可以讀取改鍵的鍵值。
2)此時DP會一直保持低電平狀態,不能再次觸發外部中斷。
3)執行init(),再次初始化TM1650,DP將恢復到高電平狀態,為下次按鍵做好準備。
1 /*************************************************** 2 *說明:恢復第16腳DP的低電平狀態 3 *備註:第一次按鍵後,DP會從高電平變成低電平狀態,只有再次初始化TM1650才能 4 * 將DP恢復成高電平狀態,從而為第二次按鍵做好準備 5 ***************************************************/ 6 void init() 7 { 8 start(); 9 wrt(COMMAND_SET_PARAMETER); 10 act(); 11 wrt(PARAMETER_SEGMENT_MODE_SEVEN | PARAMETER_WORK_MODE_RUNNING | PARAMETER_DISPLAY_MODE_ON); 12 act(); 13 stop(); 14 }
8 main函式
去掉其他功能,簡化的main函式非常簡單。
1 void main(void) 2 { 3 unsigned char key; 4 TM1650_Init(); 5 while(1) 6 { 7 if(g_FlagKeyPressed == TRUE) 8 { 9 g_FlagKeyPressed = FALSE; 10 key = TM1650_GetKeyAscii(); 11 // 處理key。。。。。。 12 } 13 } 14 }