本帖最后由 刘佑红 于 2024-10-5 08:48 编辑
使用模拟I2C顺利驱动了数码管,读取按键也正常,1637的驱动是参照天微电子提供的例程稍加修改的,但里面有2us、3us、5us的延时,在读取按键时甚至使用了两个30us长延时,我是用于电池容量测试器的,系统的主要精力在于ADC,还需不停的读取按键值,程序中的大量长延时严重拖累了系统,所以我才考虑硬件I2C。但经过多次摸索,硬件I2C始终无法点亮数码管,反复阅读天微电子的器件手册,感觉其不适用STC8H的硬件I2C驱动(?),又发现数据读写及传输没有要求那么长的延时,于是就尝试将延时改为不同数目的_nop_();然后进行实际测试,最后发现把2-30us的延时改为一个_nop_();也能正常驱动数码管,按键读取也正常。把长延时改为一个空周期,拖累系统的问题大为改观,已经满足我的需要了(起码心理没有别扭了),在发帖回复时又仔细看了一下楼上朋友的回复,才发现他已经将不同的延时改为一个_nop_();了!不认真看帖的教训呀?
发一下我改的驱动,请朋友指点与借鉴。
- #ifndef __TM1637_H__
- #define __TM1637_H__
- #include <intrins.h> //调用_nop_函数
-
- sbit SCL=P1^5;
- sbit SDA=P1^4;
-
- unsigned char code LEDA[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F, //0-9
- 0x77, //A 10
- 0x3E, //U 11
- 0x76, //H-12
- 0x73, //P 13
- 0x38, //L 14
- 0x40, //- 15
- 0x79, //E 16
- 0x00 //消隐 17
- };
-
-
- void TM1637_Start(void) //1637开始
- {
- SCL = 1;
- SDA = 1;
- _nop_();
- SDA = 0;
- }
-
- void TM1637_ack(void) //1637应答
- {
- SCL = 0;
- _nop_(); //在第八个时钟下降沿之后,开始判断 ACK 信号
- while(SDA);
- SCL = 1;
- _nop_();
- SCL = 0;
- }
-
- void TM1637_Stop(void) //1637停止
- {
- SCL = 0;
- _nop_();
- SDA = 0;
- _nop_();
- SCL = 1;
- _nop_();
- SDA = 1;
- }
-
- void TM1637_Write(unsigned char oneByte) //写一个字节
- {
- unsigned char i;
- for(i = 0;i<8;i++)
- {
- SCL = 0;
- if(oneByte&0x01) {SDA = 1;} //低位在前
- else {SDA = 0;}
- _nop_();
- oneByte = oneByte>>1;
- SCL = 1;
- _nop_();
- }
- }
-
- unsigned char TM1637_ScanKey(void) //读按键
- {
- unsigned char rekey,i;
- TM1637_Start();
- TM1637_Write(0x42); //读按键命令
- TM1637_ack();
- SDA = 1; //在读按键前拉高数据线
- for(i=0;i<8;i++) //从低位开始读
- {
- SCL = 0;
- rekey = rekey>>1;
- _nop_();
- SCL = 1;
- if(SDA) {rekey = rekey|0x80;}
- else {rekey = rekey|0x00;}
- _nop_();
- }
- TM1637_ack();
- TM1637_Stop();
- return (rekey);
- }
-
- void TM1637_Display(unsigned char a,unsigned char b,unsigned char c,unsigned char d,unsigned char e,unsigned char dp)//按顺序显示xxxx
- {
- TM1637_Start();
- TM1637_Write(0x40); //写数据+自动地址加1+普通模式
- TM1637_ack();
- TM1637_Stop();
-
- TM1637_Start();
- TM1637_Write(0xC0); //设置显示首地址即第一个LED
- TM1637_ack();
- if(dp == 3) {TM1637_Write(LEDA[a] | 0x80);} else {TM1637_Write(LEDA[a]);} //显示x.xxx,3位小数
- TM1637_ack();
- if(dp == 2) {TM1637_Write(LEDA[b] | 0x80);} else {TM1637_Write(LEDA[b]);} //显示xx.xx,2位小数
- TM1637_ack();
- if(dp == 1) {TM1637_Write(LEDA[c] | 0x80);} else {TM1637_Write(LEDA[c]);} //显示xxx.x,1位小数
- TM1637_ack();
- TM1637_Write(LEDA[d]);
- TM1637_ack();
- TM1637_Write(LEDA[e]);
- TM1637_ack();
- TM1637_Stop();
- }
-
- void TM1637_ligh(unsigned char L) //按顺序显示
- {
- TM1637_Start();
- TM1637_Write(0x88|(L-1)); //开显示,写入亮度级别
- TM1637_ack();
- TM1637_Stop();
- }
-
- #endif
复制代码
|