很多时候我们单片机入门都是从流水灯到数码管显示矩阵键盘然后基本单片机就算入门了。但在实际应用中真正用单片机直接去扫描数码管和矩阵按键的情况还是比较少的,直接扫描按键显示扫描输出占用CPU资源比较高且占用比较多的IO口。在有些实际应用中本身8位的单片机本身资源有限如STM8大部分16pin和20pin此时显示不能同时支持按键和显示。
所以专用的数码键盘IC可以很方便地和小型单片机结合使用非常方便,流行的有pd650、pt6958、sm1668等ic可以说在小家电,机顶盒,电子称等上得到广泛的使用。
最近在用做机顶盒的时候用了sm1668,感觉使用起来挺简单方便的,先将驱动记下来方便以后移植使用。
将驱动分为设备层sm1668.c sm1668.h 驱动层driver_frontpanl.c
driver_frontpanl.h
/* sm1668.h */
#ifndef _SM1668_H_
#define _SM1668_H_
typedef unsinged char U8
typedef unsinged char BOOL
typedef char S8
typedef unsinged short U16
typedef short S8
typedef unsinged int U32
typedef int S32
//===================== MARCOS FOR SM1668 BEGIN ===================================
#define LED_NUM (4)
#define DOT_ENABLE_CODE (0x80)
#define CMD_SET_DISP_MODE (0x00)
#define CMD_SET_DATA (0x40)
#define CMD_SET_ADDR (0xC0)
#define CMD_DISP_CTRL (0x80)
#define OPT_WRITE_SM1668_RAM (0x00)
#define OPT_READ_SM1668_KEYVAL (0x02)
#define ADDR_NOT_INC (0x04)
#define ADDR_AUTO_INC (0x00)
#define BRIGHTNESS_LEVEL1 (0x08)
#define BRIGHTNESS_LEVEL2 (0x09)
#define BRIGHTNESS_LEVEL3 (0x0A)
#define BRIGHTNESS_LEVEL4 (0x0B)
#define BRIGHTNESS_LEVEL5 (0x0C)
#define BRIGHTNESS_LEVEL6 (0x0D)
#define BRIGHTNESS_LEVEL7 (0x0E)
#define BRIGHTNESS_LEVEL8 (0x0F)
#define SM1668_DISP_ON (CMD_DISP_CTRL | BRIGHTNESS_LEVEL6)
#define SM1668_DISP_OFF (0x87)
#define G_LED_ON 0x10//0x80
#define G_LED_OFF 0x00
#define G_LED_ADDR 0x08
#define COLON_UP_DOT_ADDR 0x03
#define COLON_UP_DOT_ENABLE 0x01
#define COLON_UP_DOT_DISABLE 0x00
#define COLON_DOWN_DOT_ADDR 0x05
#define COLON_DOWN_DOT_ENABLE 0x01
#define COLON_DOWN_DOT_DISABLE 0x00
#define CLK_DELAY_TIME 50
enum
{
DISP_MODE_4BITS_13SEG = 0,
DISP_MODE_5BITS_12SEG,
DISP_MODE_6BITS_11SEG,
DISP_MODE_7BITS_10SEG,
}; //显示段数宏
//=====================MARCOS FOR SM1668 END===================================
typedef struct
{
U8 ledBitPos;
U8 ledCharDisp;
U8 enableDisp;
}LED_DISP_INFO;
typedef struct
{
U8 u8Char;
U8 lowByte;
U8 highByte;
}Char2Segment;
#define KEY_16 16
#define KEY_11 11
#define KEY_19 19
#define KEY_4 4
#define KEY_1 1
#define KEY_9 9
#define KEY_POWER
#define KEY_EXIT
U8 SM1668_Init(void);
void TestKey(void);
U8 SM1668_DispStr(const U8* str);
U8 UpdateLedDisp(U8 ledPos, U8 ch, U8 bEnableDot);
U16 GetKeyValue(void);
void TimeColonEn(U8 bEnable);
void work_status_OnOff(BOOL bLightOn);
void Signal_lock_OnOff(BOOL bLightOn);
void SM1668_Cls(void);
void SM1668_RamUpg(void);
void DisplayOFF(void);
void Mdrv_delay(void);
#endif /* _SM1668_H_ */
/* sm1668.h */
#include "sm1668.h"
#ifndef TRUE
#define TRUE 1
#define FALSE !TRUE
#endif
static MS_BOOL GRID1_REG = 0;
#define GPIO_ENABLE
#define SM1668_STB_H
#define SM1668_STB_L
#define SM1668_CLK_H
#define SM1668_CLK_L
#define SM1668_DATA_H
#define SM1668_DATA_L
#define SM1668_DIN_LEVEL
#define SM1668_DIN_INPUT
#define SM1668_DIN_OUTPUT
#define CLK_DELAY_TIME 50
static const Char2Segment _char2SegmentTable[] =
{
//seg A B C D E F G H
//SEG 0 1 2 3 4 5 6 7
{'0',0x3F,0x00/*0*/},
{'1',0x06,0x00/*1*/},
{'2',0x5B,0x00/*2*/},
{'3',0x4F,0x00/*3*/},
{'4',0x66,0x00/*4*/},
{'5',0x6D,0x00/*5*/},
{'6',0x7D,0x00/*6*/},
{'7',0x07,0x00/*7*/},
{'8',0x7F,0x00/*8*/},
{'9',0x6F,0x00/*9*/},
{'A',0x77,0x00/*A*/},
{'b',0x7C,0x00/*b*/},
{'C',0x39,0x00/*C*/},
{'D',0x3F,0x00/*D*/},
{'c',0x58,0x00/*c*/},
{'d',0x5E,0x00/*d*/},
{'E',0x79,0x00/*E*/},
{'F',0x71,0x00/*F*/},
{'H',0x76,0x00/*H*/},
{'h',0x74,0x00/*h*/},
{'L',0x38,0x00/*L*/},
{'n',0x54,0x00/*n*/},
{'N',0x37,0x00/*N*/},
{'o',0x5C,0x00/*o*/},
{'P',0x73,0x00/*P*/},
{'q',0x67,0x00/*q*/},
{'r',0x50,0x00/*r*/},
{'t',0x78,0x00/*t*/},
{'U',0x3E,0x00/*U*/},
{'y',0x6E,0x00/*y*/},
{'S',0x6D,0x00/*5*/},
{'s',0x6D,0x00/*5*/},
{'-',0x40,0x00/*-*/}
};
/////////////////////////////////////////////////////////////////////////////
//SM1668 turn on display
/////////////////////////////////////////////////////////////////////////////
static void _delaySomeNop(MS_U16 cnt)
{
while (cnt-->0)
{
_nop_;
_nop_;
_nop_;
_nop_;
_nop_;
}
}
/*
**@function :
**@params : value
**@return :
*/
static void __WriteByte_2_SM1668(MS_BOOL value)
{
MS_U8 i;
SM1668_CLK_H;
_delaySomeNop(CLK_DELAY_TIME);
for (i = 8; i != 0; i--)
{
if(value & 0x01)
SM1668_DATA_H;
else
SM1668_DATA_L;
SM1668_CLK_L;
_delaySomeNop(CLK_DELAY_TIME);
SM1668_CLK_H;
_delaySomeNop(CLK_DELAY_TIME);
value >>= 1;
}
}
/*
**@function : enable sm1668 disp
**@params : void
**@return : void
*/
static void __SM1668_DispOn(void)
{
SM1668_STB_L;_delaySomeNop(CLK_DELAY_TIME);
__WriteByte_2_SM1668(SM1668_DISP_ON);
SM1668_STB_H;_delaySomeNop(CLK_DELAY_TIME);
}
/*
**@function : write data to the specific ram address of SM1668
**@params : value
**@return :
*/
static void __WriteData_2_SM1668_Addr(MS_BOOL value, MS_BOOL addr)
{
_delaySomeNop(CLK_DELAY_TIME);
SM1668_STB_L; _delaySomeNop(CLK_DELAY_TIME);
__WriteByte_2_SM1668(CMD_SET_DATA | ADDR_NOT_INC);
SM1668_STB_H;_delaySomeNop(CLK_DELAY_TIME);
__WriteByte_2_SM1668(CMD_SET_ADDR | addr);
__WriteByte_2_SM1668(value);
SM1668_STB_H;_delaySomeNop(CLK_DELAY_TIME);
__SM1668_DispOn();
_delaySomeNop(CLK_DELAY_TIME);
}
/*
**@function : clear all the SM1668 ram, if we want to display a new char
**@params : no
**@return : no
*/
static void Mdrv_Clear_sm16668_RAM(void)
{
MS_U16 i;
SM1668_STB_L;
_delaySomeNop(CLK_DELAY_TIME);
__WriteByte_2_SM1668(CMD_SET_DATA | ADDR_AUTO_INC);
SM1668_STB_H;
_delaySomeNop(CLK_DELAY_TIME);
SM1668_STB_L;
_delaySomeNop(CLK_DELAY_TIME);
__WriteByte_2_SM1668(CMD_SET_ADDR | 0x00);
for (i = 14; i != 0; i--)
{
__WriteByte_2_SM1668(0x00);
}
SM1668_STB_H;
_delaySomeNop(CLK_DELAY_TIME);
}
BOOL SM1668_Init(void)
{
volatile MS_U16 i;
SM1668_STB_H;
SM1668_CLK_H;
SM1668_DATA_H;
for (i = 10000; i != 0; i--)
_delaySomeNop(CLK_DELAY_TIME);
Mdrv_FP_SM1668_Cls();
Mdrv_Clear_CT16668_RAM();
SM1668_STB_L;
_delaySomeNop(CLK_DELAY_TIME);
__WriteByte_2_SM1668(0x03);
SM1668_STB_H;
_delaySomeNop(CLK_DELAY_TIME);
__SM1668_DispOn();
GRID1_REG = 0;
return TRUE;
}
/*
**@function : get CD code for led disp
**@params : whilch char want to disp
**@return : char's BCD code
*/
static MS_BOOL __GetCharCode(MS_BOOL ch)
{
const Char2Segment *ptbl;
for (ptbl = _char2SegmentTable;
ptbl < (_char2SegmentTable + sizeof(_char2SegmentTable) / sizeof(Char2Segment)); ptbl++)
{
if (ch == ptbl->u8Char)
{
return ptbl->lowByte;
}
}
//need promt invalid char?
return 0xFF;
}
/* disp function */
U8 dispBuf[8]; //disp buffer
void sm1668_clear_dispbuf(void)
{
MS_U8 i;
for (i = 0; i < 8; i++)
{
dispBuf[i] = 0x00;
}
}
/*
**@function : disp string
**@params : no
**@return : no
*/
BOOL sm1668_DispStr(const MS_U8* str)
{
MS_U8 charPos = 4;
const MS_U8 *pStrEnd;
for (pStrEnd = str; '