使用辉芒的TF61E145,通过IIC驱动TM1650控制KD5641AU-07共阴数码管和按键
代码如下
//Project: KeyBoard.prj
// Device: FT61E14X
// Memory: Flash 4KX14b, EEPROM 128X8b, SRAM 512X8b
// Author:
//Company:
//Version:
// Date:
//===========================================================
//===========================================================
#include "SYSCFG.h"
//===========================================================
//Variable definition
volatile char W_TMP @ 0x70 ;//系统占用不可以删除和修改
volatile char BSR_TMP @ 0x71 ;//系统占用不可以删除和修改
void user_isr();//用户中断程序,不可删除
void TM1650_Display_Clear(void);
void TM1650_Display_One(unsigned char pos, unsigned char data);
void _TM1650_Init (unsigned char add,unsigned char data);
void Update_Display(void);
void LED_Blink_101010(void);
void LED_Wait_Ack_1010(void);
void TM1650_SetBrightness(unsigned char level);
//===========================================================
//===========================================================
//Function name:interrupt ISR
//parameters:无
//returned value:无
//===========================================================
void interrupt ISR(void)
{
#asm;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
NOP;//系统设置不可以删除和修改
#endasm;//系统设置不可以删除和修改
user_isr(); //用户中断函数
}
void user_isr() //用户中断函数
{
}
//***********************宏定义*****************************
#define unchar unsigned char
#define unint unsigned int
#define unlong unsigned long
#define READ_PIN(port, pin) (((port) & (1 << (pin))) ? 1 : 0)
#define READ_SDAT_PORT READ_PIN(PORTB, 1)
#define IIC_SCL RB0
#define IIC_SDA RB1
#define SDA_OUT TRISB1 =0
#define SDA_IN TRISB1 =1
#define LED RC0
//全局查看变量定义
volatile unchar IICReadData;
/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能: 上电系统初始化
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void POWER_INITIAL (void)
{
OSCCON = 0B01110001; //WDT 32KHZ IRCF=111=16MHZ
//Bit0=1,系统时钟为内部振荡器
//Bit0=0,时钟源由FOSC<2:0>决定即编译选项时选择
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000;
TRISA = 0B11100111; //PA输入输出 0-输出 1-输入
PORTB = 0B00000000;
TRISB = 0B11111100; //PB输入输出 0-输出 1-输入++++++
PORTC = 0B00000000;
TRISC = 0B11111110; //PC输入输出 0-输出 1-输入
WPUA = 0B00000000; //PA端口上拉控制 1-开上拉 0-关上拉。弱上拉电阻
WPUB = 0B00000000; //PB端口上拉控制 1-开上拉 0-关上。弱上拉电阻
WPUC = 0B00000000; //PC端口上拉控制 1-开上拉 0-关上。弱上拉电阻
WPDA = 0B00000000; //PA端口上拉控制 1-开下拉 0-关下拉内部弱下拉电阻
WPDB = 0B00000000; //PB端口上拉控制 1-开下拉 0-关? 内部弱下拉电阻
WPDC = 0B00000000; //PC端口上拉控制 1-开下拉 0-关下内部弱下拉电阻
PSRC0 = 0B11111111; //PORTA,PORTB源电流设置最大
//BIT7~BIT6:PORTB[7:4]源电流能力控制,BIT5~BIT4:PORTB[3:0]源电流能力控制
//BIT3~BIT2:PORTA[7:4]源电流能力控制,BIT1~BIT0:PORTA[3:0]源电流能力控制
PSRC1 = 0B11111111; //PORTC,PORTD源电流设置最大
//BIT7~BIT6:PORTD[7:4]源电流能力控制,BIT5~BIT4:PORTD[3:0]源电流能力控制
//BIT3~BIT2:PORTC[7:4]源电流能力控制,BIT1~BIT0:PORTC[3:0]源电流能力控制
PSINK0 = 0B11111111; //PORTA灌电流设置最大 0:最小,1:最大
PSINK1 = 0B11111111; //PORTB灌电流设置最大 0:最小,1:最大
PSINK2 = 0B11111111; //PORTC灌电流设置最大 0:最小,1:最大
ANSELA = 0B00000000; //全为数字管脚
}
/*-------------------------------------------------
* 函数名称:DelayUs
* 功能: 短延时函数 --16M-2T--大概快1%左右.
* 输入参数:Time延时时间长度 延时时长Time Us
* 返回参数:无
-------------------------------------------------*/
void DelayUs(unsigned char Time)
{
unsigned char a;
for(a=0;a<Time;a++)
{
NOP();//16MHZ的MCU一个NOP为62.5纳秒
}
}
/*-------------------------------------------------
* 函数名称:DelayMs
* 功能: 短延时函数
* 输入参数:Time延时时间长度 延时时长Time ms
* 返回参数:无
-------------------------------------------------*/
void DelayMs(unsigned char Time)
{
unsigned char a,b;
for(a=0;a<Time;a++)
{
for(b=0;b<5;b++)
{
DelayUs(197); //快1%
}
}
}
/*-------------------------------------------------
* 函数名称:DelayS
* 功能: 短延时函数
* 输入参数:Time延时时间长度 延时时长Time S
* 返回参数:无
-------------------------------------------------*/
void DelayS(unsigned char Time)
{
unsigned char a,b;
for(a=0;a<Time;a++)
{
for(b=0;b<10;b++)
{
DelayMs(100);
}
}
}
/*-------------------------------------------------
* 函数名:IIC_Start
* 功能: 产生IIC起始信号
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void IIC_Start(void)
{
SDA_OUT; //SDA线输出0
IIC_SDA=1;
IIC_SCL=1;
DelayUs(4);
IIC_SDA=0; //START:when CLK is high,DATA change form high to low
DelayUs(4);
IIC_SCL=0; //钳住I2C总线,准备发送或接收数据
DelayUs(4);
}
/*-------------------------------------------------
* 函数名:IIC_Stop
* 功能: 产生IIC停止信号
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void IIC_Stop(void)
{
SDA_OUT; //SDA线输出
IIC_SCL=0;
IIC_SDA=0; //STOP:when CLK is high DATA change form low to high
DelayUs(4);
IIC_SCL=1;
DelayUs(4);
IIC_SDA=1; //发送I2C总线结束信号
DelayUs(4);
}
///*-------------------------------------------------
// * 函数名:IIC_Wait_Ack
// * 功能: 等待应答信号到来
// * 输入: 无
// * 输出: 返回值:1,接收应答失败
// * 0,接收应答成功
// --------------------------------------------------*/
//unsigned char IIC_Wait_Ack(void)
//{
// unsigned char ucErrTime=0;
// SDA_IN; //SDA设置为输入
// IIC_SDA=1;
// DelayUs(2);
// IIC_SCL=1;
// DelayUs(2);
// while(IIC_SDA)
// {
// ucErrTime++;
// if(ucErrTime>100) //等待超时
// {
// IIC_Stop();
// LED_Wait_Ack_1010();
// return 1;
// }
// }
// IIC_SCL=0; //时钟输出0
// return 0;
//}
///*-------------------------------------------------
// * 函数名:IIC_Ack
// * 功能: 产生ACK应答
// * 输入: 无
// * 输出: 无
// --------------------------------------------------*/
//void IIC_Ack(void)
//{
// IIC_SCL=0;
// SDA_OUT; //SDA线输出
// IIC_SDA=0;
// DelayUs(2);
// IIC_SCL=1;
// DelayUs(2);
// IIC_SCL=0;
//}
///*-------------------------------------------------
// * 函数名:IIC_NAck
// * 功能: 不产生ACK应答
// * 输入: 无
// * 输出: 无
// --------------------------------------------------*/
//void IIC_NAck(void)
//{
// IIC_SCL=0;
// SDA_OUT; //SDA线输出
// IIC_SDA=1;
// DelayUs(2);
// IIC_SCL=1;
// DelayUs(2);
// IIC_SCL=0;
//}
//IIC总线复位
void I2c_ResetBus(void)
{
SDA_OUT;
IIC_SDA=1;
for(int i=0;i<9;i++)
{
IIC_SCL=1;
DelayUs(10);
IIC_SCL=0;
DelayUs(10);
}
IIC_Start();
}
/*-------------------------------------------------
* 函数名:IIC_Send_Byte
* 功能: IIC发送一个字节
* 输入: 写入要发送的一个人字节数据txd
* 输出: 无
--------------------------------------------------*/
void IIC_Send_Byte(unsigned char txd)
{
unsigned char t;
SDA_OUT; // SDA线输出
IIC_SCL = 0; // 拉低时钟开始数据传输
for(t = 0; t < 8; t++)
{
if((txd & 0x80) >> 7)
{
IIC_SDA = 1;
}
else
{
IIC_SDA = 0;
}
txd <<= 1; // 左移数据位
DelayUs(4);
IIC_SCL = 1; // 产生时钟上升沿
DelayUs(4);
IIC_SCL = 0; // 产生时钟下降沿
DelayUs(2);
}
SDA_IN;
IIC_SCL = 1;
DelayUs(2);
int timeout = 1000; // 超时 1ms
while (READ_SDAT_PORT && timeout--) {
DelayUs(2);
}
IIC_SCL = 0;
SDA_OUT;
if (timeout==0)
{
I2c_ResetBus();
}
}
/*-------------------------------------------------
* 函数名:IIC_Read_Byte
* 功能: IIC读一个字节
* 输入: 无
* 输出: 读出存储器里面的数据并返回receive
--------------------------------------------------*/
unsigned char IIC_Read_Byte(void)
{
unsigned char i,receive=0;
SDA_IN; //SDA设置为输入,1
IIC_SDA=1;
for(i=0;i<8;i++ )
{
receive<<=1;
IIC_SCL=1;
DelayUs(5);
if(IIC_SDA)receive |0x01;
IIC_SCL=0;
DelayUs(4);
}
SDA_OUT;
IIC_SDA=1;
IIC_SCL=1;
DelayUs(5);
IIC_SCL=0;
SDA_IN;
IIC_SDA=1;
return receive;
}
/*=================================TM1650====================================*/
//TM1650
#define TM1650_display_cmd 0x48 //发送模式命令
#define TM1650_key_read_cmd 0x49 //按键读取命令
//显存地址定义
#define TM1650_DIG1_ADDR 0x68
#define TM1650_DIG2_ADDR 0x6A
#define TM1650_DIG3_ADDR 0x6C
#define TM1650_DIG4_ADDR 0x6E
// 显示控制命令
#define TM1650_DISPLAY_ON 0x01 // 开显示
#define TM1650_DISPLAY_OFF 0x00 // 关显示
// 按键定义
#define KEY_S1 0x4C
#define KEY_S2 0x4D
#define KEY_S3 0x5E
#define KEY_S4 0x44
#define KEY_S5 0x45
#define KEY_S6 0x46
#define KEY_S7 0x64
#define KEY_S8 0x65
#define KEY_S9 0x66
#define KEY_S10 0x74
#define KEY_S11 0x75
#define KEY_S12 0x76
#define KEY_S13 0x6C
#define KEY_S14 0x6D
#define KEY_S15 0x6E
// 全局变量 - 存储当前显示的数字和位数
unsigned char display_number[4] = {0, 0, 0, 0}; // 最多4位数
unsigned char current_digits = 0; // 当前位数(0-4)
const unsigned char seg_code[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
void LED_Blink_101010(void)
{
LED = 1;
DelayMs(100);
LED = 0;
DelayMs(100);
LED = 1;
DelayMs(100);
LED = 0;
DelayMs(100);
LED = 1;
DelayS(3);
LED = 0;
}
void LED_Wait_Ack_1010(void)
{
LED = 1;
DelayMs(100);
LED = 0;
DelayMs(100);
LED = 1;
DelayS(3);
LED = 0;
}
//TM1650初始化
void _TM1650_Init (unsigned char add,unsigned char data)
{
IIC_Start();
IIC_Send_Byte(add);
IIC_Send_Byte(data);//0x09
//8级亮度 \7段\正常工作\开屏
IIC_Stop();
}
void power_init (unsigned char sdate1, unsigned char sdate2, unsigned char sdate3, unsigned char sdate4)
{
_TM1650_Init(0X68,sdate1);
_TM1650_Init(0X6A,sdate2);
_TM1650_Init(0X6C,sdate3);
_TM1650_Init(0X6E,sdate4);
}
//S15按键,清空数码管
void TM1650_Display_Clear(void)
{
display_number[0] = 0;
display_number[1] = 0;
display_number[2] = 0;
display_number[3] = 0;
current_digits = 0;
TM1650_Display_One(1, 0x00); // 关闭第1位数码管
TM1650_Display_One(2, 0x00); // 关闭第2位数码管
TM1650_Display_One(3, 0x00); // 关闭第3位数码管
TM1650_Display_One(4, 0x00); // 关闭第4位数码管
}
//TM1650显示亮度
void TM1650_SetBrightness(unsigned char level)
{
if(level>7)level=7;
IIC_Start();
IIC_Send_Byte(TM1650_display_cmd);
IIC_Wait_Ack();
IIC_Send_Byte(0x01|(level<<4));
IIC_Wait_Ack();
IIC_Stop();
}
//显示单个数码管
void TM1650_Display_One(unsigned char pos,unsigned char data )
{
unsigned char addr;
switch (pos)
{
case 1:
addr=TM1650_DIG1_ADDR;
break;
case 2:
addr=TM1650_DIG2_ADDR;
break;
case 3:
addr=TM1650_DIG3_ADDR;
break;
case 4:
addr=TM1650_DIG4_ADDR;
break;
default:
addr=TM1650_DIG1_ADDR;
break;
}
IIC_Start();
IIC_Send_Byte(addr);
IIC_Send_Byte(data);
IIC_Stop();
}
//显示数字
void TM1650_Display_Number(unsigned char num)
{
if(num > 9) num = 0;
unsigned char data = seg_code[num];
//数字左移逻辑
if(current_digits >= 4)
{
// 如果已经显示4位,则左移丢弃最高位,新数字加到最低位
for(unsigned char i = 3; i > 0; i--)
{
display_number[i] = display_number[i-1];
}
display_number[0] = num;
}
else//<4
{
// 左移现有数字
for(unsigned char i = current_digits; i > 0; i--)
{
display_number[i] = display_number[i-1];
}
// 添加新数字到最低位
display_number[0] = num;
current_digits++;
}
// 更新显示
Update_Display();
}
//更新数码管显示
void Update_Display(void)
{
// 更新4位数码管显示
for(unsigned char i = 0; i < 4; i++)
{
if(i < current_digits)
{
TM1650_Display_One(i+1, seg_code[display_number[i]]);
}
else
{
TM1650_Display_One(i+1, 0x00); // 关闭未使用的数码管
}
}
}
#define NUM_KEYS 15
const unsigned char keys[NUM_KEYS] = {KEY_S1, KEY_S2, KEY_S3, KEY_S4, KEY_S5,
KEY_S6, KEY_S7, KEY_S8, KEY_S9, KEY_S10,
KEY_S11, KEY_S12, KEY_S13, KEY_S14, KEY_S15};
// S10按键,当前数字减一位
// S12按键,当前数字加一位
// S13按键,配码
// S14按键,响铃呼叫
//接收从机发送的按键扫描码
unsigned char ReceiveKeyScanCode(void)
{
unsigned char key_scan_code=0xFF;
IIC_Start();
IIC_Send_Byte(TM1650_key_read_cmd);//0x49
key_scan_code=IIC_Read_Byte();
IIC_Stop();
for (int i = 0; i < NUM_KEYS; i++) {
if (key_scan_code == keys[i]) {
LED_Blink_101010();
}
}
// if(key_scan_code==0x2E)
// {
// LED_Blink_101010();
// }
return key_scan_code;
}
//所有处理按键事件
void Process_Key(unsigned char key)
{
switch(key)
{
case 0x4C: TM1650_Display_Number(1); //KEY_S1
break;
case 0x4D: TM1650_Display_Number(2); //KEY_S2
break;
case 0x5E: TM1650_Display_Number(3); //KEY_S3
break;
case 0x44: TM1650_Display_Number(4); //KEY_S4
break;
case 0x45: TM1650_Display_Number(5); //KEY_S5
break;
case 0x46: TM1650_Display_Number(6); //KEY_S6
break;
case 0x64: TM1650_Display_Number(7); //KEY_S7
break;
case 0x65: TM1650_Display_Number(8); //KEY_S8
break;
case 0x66: TM1650_Display_Number(9); //KEY_S9
break;
// case 0x74: //KEY_S10
// break;
case 0x75:TM1650_Display_Number(0); //KEY_S11
break;
// case 0x76: //KEY_S12
// break;
// case 0x6C: //KEY_S13
// break;
// case 0x6D: OFF_NO(); //KEY_S14
// break;
case 0x6E:
TM1650_Display_Clear(); //KEY_S15
break;
default: break;
}
}
//===========================================================
//Function name:main
//parameters:无
//returned value:无
//===========================================================
main()
{
POWER_INITIAL(); //系统初始化
_TM1650_Init(0x48,0x09); // 初始化TM1650
power_init(0x3F, 0x06, 0x5B, 0x4F);
TM1650_Display_Clear();//上电清零
while(1)
{
// 读取按键状态
unsigned char key =ReceiveKeyScanCode();
if(key != 0)
{
// 有按键按下,处理按键
Process_Key(key);
//防抖
DelayMs(5);
while(ReceiveKeyScanCode() != 0); // 等待按键释放
DelayMs(5);
}
DelayMs(5000);
}
return 0;
}
//=====================
上述代码,在执行到_TM1650_Init(0x48,0x09);和power_init(0x3F, 0x06, 0x5B, 0x4F); 的时候,为何开发板分别显示这样,请问是什么原因,如何解决

