天天看點

TM1640 數位管驅動代碼(簡化版)

/*TM1640的SRAM寫資料格式-----------
 B7 B6 0 0 - - - -
  0  1 0 0 - - - -  尋址模式(1 Byte)
  1  1 0 0 - - - -  顯存位址(1 Byte)
  data 1~N          資料傳輸(最多16 Byte) 固定位址時為一位址一資料
  1  0 0 0 - - - -  顯示控制(1 Byte)
 指令類型:
            B7 B6 - - - - - -
 尋址模式:  0  1  
 顯示控制:  1  0  
 顯存位址:  1  1  
---------------------------------*/
#define DATA_MODE_AUTO   0x40  //位址自動加1/普通模式
#define DATA_MODE_FIXED  0x44  //固定位址
#define DATA_MODE_TEST   0x48  //測試模式
/*尋址模式-------------------------
 自動位址+1: 01000000            0x40
 固定位址  : 01000100            0x44
 普通模式  : 01000000            0x40
 測試模式  : 01001000 (内部使用) 0x48
---------------------------------*/

#define DIS_EN     0x8A  //顯示開
#define DIS_DIS    0x80  //顯示關
/*顯示控制-------------------------
           B7 B6 - - B3 B2 B1 B0 (脈沖寬度)
 顯示開關: 1  0  0 0 0  -  -  -  顯示關  0x80
           1  0  0 0 1  -  -  -  顯示開  0x88
 消光數量: 1  0  0 0 1  0  0  0    1/16  0x88
 (即亮度)  1  0  0 0 1  0  0  1    2/16  0x89
           1  0  0 0 1  0  1  0    4/16  0x8A
           1  0  0 0 1  0  1  1   10/16  0x8B
           1  0  0 0 1  1  0  0   11/16  0x8C
           1  0  0 0 1  1  0  1   12/16  0x8D
           1  0  0 0 1  1  1  0   13/16  0x8E
           1  0  0 0 1  1  1  1   14/16  0x8F
---------------------------------*/

/*顯存位址-------------------------
           B7 B6 - - B3 B2 B1 B0 (顯示單元)
     0xC0  1  1  0 0 0  0  0  0  GRID1
     0xC1  1  1  0 0 0  0  0  1  GRID2
     0xC2  1  1  0 0 0  0  1  0  GRID3
     0xC3  1  1  0 0 0  0  1  1  GRID4
     0xC4  1  1  0 0 0  1  0  0  GRID5
     0xC5  1  1  0 0 0  1  0  1  GRID6
     0xC6  1  1  0 0 0  1  1  0  GRID7
     0xC7  1  1  0 0 0  1  1  1  GRID8
     0xC8  1  1  0 0 1  0  0  0  GRID9
     0xC9  1  1  0 0 1  0  0  1  GRID10
     0xCA  1  1  0 0 1  0  1  0  GRID11
     0xCB  1  1  0 0 1  0  1  1  GRID12
     0xCC  1  1  0 0 1  1  0  0  GRID13
     0xCD  1  1  0 0 1  1  0  1  GRID14
     0xCE  1  1  0 0 1  1  1  0  GRID15
     0xCF  1  1  0 0 1  1  1  1  GRID16
---------------------------------*/

#define FIRST_ADDR  0xC0  //起始位址

/*======================================================================
 函數/功能主題描述/端口及常量、變量定義
======================================================================*/
// 端口定義
sbit DisDIN   =   P3^2;
sbit DisCLK   =   P3^3;
/*---------------------------------
 DIN : 顯示端口-資料端
 DisCLK: 顯示端口-時鐘端
---------------------------------*/

u8 DisBuf[16];     // 顯示緩存
/*---------------------------------
 各顯示單元描述

…
---------------------------------*/

u8 code SegCode[]={
    //0x3F, 0x06, 0x5B, 0x4F, 0x66,  //  0~ 4: 0 1 2 3 4
    //0x6D, 0x7D, 0x07, 0x7F, 0x6F,  //  5~ 9: 5 6 7 8 9
    //0x77, 0x7C, 0x39, 0x5E, 0x79,  // 10~14: A b C d E
    //0x71, 0x76, 0x38, 0x50, 0x54,  // 15~19: F H L r n
    //0x1C, 0x73, 0x5C, 0x40, 0x00   // 20~24: u P o - null(熄滅)
};
           
TM1640 數位管驅動代碼(簡化版)

端口驅動函數:

/**=====================================================================
 驅動功能函數
 SCLK: ──┐                   SCLK:  ┌──
         └─                        ─┘
  DIN: ─┐    //開始           DIN:   ┌─  //結束
        └──                        ──┘
          7   6   5   4   3   2   1   0
 傳輸:   ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─
       ──┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
        ┌───┐───┌───┐───┌───┐───┌───┐───┐ ┌
       ─┘───└───┘───└───┘───└───┘───└───┘─┘  
          7   6   5   4   3   2   1   0
=====================================================================**/
//開始-----------------------------
void start(void){  //首次開始前(初始化期間)先觸發1次結束, 以使SCLK=1, DIN=1
  DisDIN = 0;      //DIN由H→L, 開始
  DisCLK = 0;      //置SCLK為L, 為發送DIN位作準備
}
//發送資料-------------------------
void Send_DisDat(u8 dx){
  u8 i;
  for(i=0; i<8; i++){          //開始時已置SCLK=0
    DisDIN = (bit)(dx & 0x01); //發送位, 低位先傳
    DisCLK = 1;                //位發送結束-DIN信号保持
    dx   >>= 1;
    DisCLK = 0;                //置SCLK=0, 為發送下一位/結束準備
  }
  //DisDIN = 0;               //該條語句與結束函數中的首條重複, 故可省掉
}
//結束-----------------------------
void stop(void){
  DisDIN = 0;
  DisCLK = 1;                  //置SCLK為H-結束準備
  DisDIN = 1;                  //DIN由L→H, 結束, 為下一次開始準備
}
           

注:以上三段函數省掉了不必要的語句,但須在初始化階段完成端口電平的就緒狀态(也即是結束資料傳輸後的狀态)。

實際運作的資料信号波形(黃色為SCLK,青色為DIN):

TM1640 數位管驅動代碼(簡化版)
TM1640 數位管驅動代碼(簡化版)

提示:根據TM1640的規格書說明——CLK為高電平時,DIN高電平->低電平即為開始;CLK為高電平時,DIN低電平->高電平即為結束。換句話說就是,TM1640在下降沿捕捉開始信号,上升沿捕捉結束信号,且開始/結束信号的捕捉區間為CLK處于高電平時。 CLK處于低電平時為 資料信号的捕捉區間,且捕捉發生在CLK的上升沿。

為何要分為三段函數,而不是将它們合為一個函數?

因為在發送位資料的過程中有單位元組和多位元組資料 的區分,當然可以使用2層循環及使用指針傳送單位元組資料或數組位址來解決,比如下面的代碼。但是,使用2層循環會涉及循環變量及必要的邏輯判斷,且會消耗過多的執行時間,單單循環内末語句結束到退出循環——循環結束,就得10來個機器周期的時間,還不如使用函數調用(2~4個機器周期即完成)。

提示:對于底層操作代碼,每一個多餘的指令都會對直接影響上層操作代碼的執行效率——若底層代碼包含1條備援代碼,上層代碼調用時可能會執行n多次該備援代碼。 簡單來說,“一個很小的基數乘以一個很大的倍數”的問題對于底層 代碼來說應需重視。

//資料緊湊發送---------------------
void sendDisDat(u8 *p){
  u8 i, j, dat, len;
  len = sizeof(p);
  //---------------------------開始
  DisDIN = 0;      //DIN由H→L, 開始
  DisCLK = 0;      //置SCLK為L, 為發送DIN位作準備
  //-----------------------發送資料
  for(i=0; i<len; i++){       //開始時已置SCLK=0
    if(len==1){dat = p;}else{dat = p[i];}  //單位元組時指針值即為資料值,多位元組時指針值為數組位址
    for(j=0; j<8; j++){
      DisDIN   = (bit)(dat & 0x01); //發送位
      DisCLK   = 1;                 //位發送結束-DIN信号保持
      dat >>= 1;
      DisCLK   = 0;                 //置SCLK=0, 為發送下一位/結束準備
    }
  }
  //---------------------------結束
  DisDIN = 0;
  DisCLK = 1;                  //置SCLK為H-結束準備
  DisDIN = 1;                  //DIN由H→L, 結束, 為下一次開始準備
}
           

 資料據操作函數:

/**=====================================================================
 函數名稱: Update_DisDat
 輸    入: addr-顯存位址, dx-8位位址資料
 功能描述: 更新dx指定的位址的資料
 說    明: 
=====================================================================**/
void Update_DisDat(u8 addr, u8 dx){
  start(); Send_DisDat(DATA_MODE_FIXED); stop(); //固定位址
  start();
    Send_DisDat(addr);                           //指定位址
    Send_DisDat(DisBuf[dx]);                     //資料傳輸-1字元
  stop();
}

/**=====================================================================
 函數名稱: UpdateAllDisDat
 輸    入: 無
 功能描述: 更新所有顯示資料
 說    明: 
=====================================================================**/
void UpdateAllDisDat(void){
  u8 i;
  //start(); Send_DisDat(DIS_DIS);        stop(); //顯示關
  start(); Send_DisDat(DATA_MODE_AUTO); stop(); //自動位址
  start(); Send_DisDat(FIRST_ADDR);             //起始位址
  for(i=0; i<15; i++){                          //資料傳輸開始-15字元
    Send_DisDat(DisBuf[i]);
  }
  stop();                                       //資料傳輸結束
  //start(); Send_DisDat(DIS_EN);         stop(); //顯示開
}

/**=====================================================================
 函數名稱: DisBufFresh
 輸    入:  dat[]-計數器
 功能描述: 錯誤時對應的編号閃爍
 說    明: 
=====================================================================**/
void DisBufFresh(u8 *dat){
  //顯示緩沖更新代碼
}
           

初始化函數:

/**=====================================================================
 函數名稱: Dis_Init()
 輸    入: 無
 功能描述: 顯示緩沖及驅動初始化
 說    明: 
=====================================================================**/
void DisBufInit(void){
  u8 i;
  stop();                               //觸發1次結束, 以使SCLK=1, DIN=1
  start(); Send_DisDat(DIS_EN); stop(); //顯示開
  for(i=0; i<16; i++){
    DisBuf[i]  = SegCode[24];           //全部熄滅
  }
  UpdateAllDisDat();
}