API650E显示驱动
前言
应用于51单片机
一、API650E显示驱动端口配置
首先对端口进行配置,默认可以选择为强推挽输出模式,其中SDA端口根据API650E芯片使用手册可以得到,需要将其在恰当的时候配置为输入模式。
因此需要将SDA在接收8位数据以后,将IO口配置为输入,然后再将SDA手动置“0”,(结合波形分析出,下面会详细阐述这一点)。
配置端口代码如下:
//宏定义SDA端口和SCL端口
P2CON |= 0x20; P2PH |= 0x00; //2.5-SDA-默认为强推挽输出
P2CON |= 0x40; P2PH |= 0x00; //2.6-SCL-默认为强推挽输出
//SDA端口
#define AIP650E_SDA_OUTPUT {P2CON |= 0x20; P2PH |= 0x00;} //2.5配置为输出
#define AIP650E_SDA_INPUT {P2CON |= 0x00; P2PH |= 0x20;} //2.5配置为输入
#define IO_SDA_PIN (P25)
#define IO_SCL_PIN (P26)
#define OUT_AIP650E_SDA(sig) { if(sig>0){IO_SDA_PIN = 1;} else {IO_SDA_PIN = 0;} }
#define OUT_AIP650E_SCL(sig) { if(sig>0){IO_SCL_PIN = 1;} else {IO_SCL_PIN = 0;} }
二、延时函数
以下是本段代码用到的延时,使用Nop语句,注意:在51单片机中写成“nop()”,区别于32单片机。
void f_NOPDelay(uint16_t i_Value)
{
uint16_t i;
for (i = 0; i < i_Value; i++)
{
_nop_();
}
}
static void f_AIP650E_Delay(void)
{
f_NOPDelay(5); /* Nop延时函数 */
}
三、模拟IIC起始、终止信号
从芯片手册中可以看出两个端口都是先高电平,接着是低电平,最后才开始数据的传输。因此在起始信号配置中,如以下代码中所示首先是高电平,然后延时一段时间后变成低电平。
- 起始信号
//功能描述: 根据数据手册得出**起始信号**以下配置
void f_AIP650E_SendStart(void)
{
AIP650E_SDA_OUTPUT;
OUT_AIP650E_SDA(1);
OUT_AIP650E_SCL(1);
f_AIP650E_Delay();
OUT_AIP650E_SDA(0);
f_AIP650E_Delay();
OUT_AIP650E_SCL(0);
}
- 起始信号
void f_AIP650E_SendStop(void)
{
AIP650E_SDA_OUTPUT;
OUT_AIP650E_SDA(0);
OUT_AIP650E_SCL(0);
f_AIP650E_Delay();
OUT_AIP650E_SCL(1);
f_AIP650E_Delay();
OUT_AIP650E_SDA(1);
}
四、模拟应答信号
由于本人也是小白,因此在应答信号这里进行了一些分析。
主要的目的是对以下这两行代码的分析
OUT_AIP650E_SDA(0);
OUT_AIP650E_SDA(1);
原因:在芯片手册中可以看到,
“本电路的数据传输带有应答信号 ACK,在传输数据的过程中,在时钟线的第九个时钟芯片内部会产生一个应答信号 ACK 将 DIO(SDA) 管脚拉低。无论是命令写入或者是数据写入读出时,在一个 8 位字节后的第 9 位都是 ACK 信号输出。”
在进行数据传送时,在SCL的上升沿锁存数据,SCL为高电平期间,SDA线上的数据必须保持稳定,只有在SCL线上的信号为低电平期间,SDA线上的数据状态才允许改变,且SDA线上的数据不能在SCL为下降沿改变。
1.屏蔽OUT_AIP650E_SDA()的时序图
因为是第一次使用模拟IIC,对“模拟”理解的不太深入,因此认为接收8为数据以后芯片会发出一个低电平信号给SDA,只需要主控芯片读出该低电平信号就行。(此时已经将SDA端口配置为输入**(对主控芯片来说)**)。因此第一次将直接就将该行代码屏蔽,只是将SDA配置为输入,源码如下:
u8 f_AIP650E_Wait_Ack(void)
{
u8 ucErrTime=0;
AIP650E_SDA_INPUT;
// OUT_AIP650E_SDA(0);
// OUT_AIP650E_SDA(1);
f_AIP650E_Delay();
OUT_AIP650E_SCL(1);
f_AIP650E_Delay();
while(IO_SDA_PIN)
{
ucErrTime++;
if(ucErrTime>250)
{
f_AIP650E_SendStop();
return 1; //表示传输出问题了,不能在继续显示了。
}
}
OUT_AIP650E_SCL(0);
return 0;
}
//发送一次数据的代码
void f_AIP650E_Send_Byte(uint8_t i_Data)
{
uint8_t i;
AIP650E_SDA_OUTPUT;
OUT_AIP650E_SCL(0);
f_AIP650E_Delay();
for(i = 0; i < 8; i++)
{
if((i_Data & 0x80) >> 7)
{
OUT_AIP650E_SDA(1);
}
else
{
OUT_AIP650E_SDA(0);
}
i_Data <<= 1;
f_AIP650E_Delay();
OUT_AIP650E_SCL(1);
f_AIP650E_Delay();
OUT_AIP650E_SCL(0);
f_AIP650E_Delay();
}
}
//整个过程。
extern uint8_t WriteOneByte(uint8_t SlaverAddr,uint8_t DataToWrite)
{
uint8_t ErrFlag = 0;
f_AIP650E_SendStart();
f_AIP650E_Send_Byte(SlaverAddr);
ErrFlag = f_AIP650E_Wait_Ack();
if(ErrFlag == 1)
return ErrFlag;
f_AIP650E_Send_Byte(DataToWrite);
ErrFlag = f_AIP650E_Wait_Ack();
if(ErrFlag == 1)
return ErrFlag;
f_AIP650E_SendStop();
return 0;
}
//再试用过程中只需要调用该函数即可,其中调用之前,需要进行一次初始化,参考芯片手册,本文选择的是0x4871。
WriteOneByte(0x48,0x71);
WriteOneByte(0x6E,0x80);
以下是波形分析:
第一次传输的数据是0x6E,在传输完成以后需要一个ACK信号,本身第一次的数据最低位是“0”,虽然将该端口配置了上拉电阻输入,但是依旧保持低电平,因此被SCL锁存到,完成了一次应答。接着进行0x80数据传输。结合源码可以清晰的分析出这段时序图,本文就不在详细赘述。分析的整体思路就是:
-
首先需要明白数据的地方就是图中标记的,黄色代表SCK(时钟线),绿色代表的是数据线。
-
为什么数据可以有效传递,这是因为芯片手册中明确说明了“SCK(时钟线)由低到高的过程才能有效的传递数据”,
-
结合程序以及上述图片内容一步一步认真的走程序,就可以完整的分析上述的时序图,分析完以后代表了你彻底理解了针对AIP650E显示芯片模拟IIC传输过程。
2.OUT_AIP650E_SDA(1)的时序图
以下是源码:
u8 f_AIP650E_Wait_Ack(void)
{
u8 ucErrTime=0;
AIP650E_SDA_INPUT;
OUT_AIP650E_SDA(1);
f_AIP650E_Delay();
OUT_AIP650E_SCL(1);
f_AIP650E_Delay();
while(IO_SDA_PIN)
{
ucErrTime++;
if(ucErrTime>250)
{
f_AIP650E_SendStop();
return 1;
}
}
OUT_AIP650E_SCL(0);
return 0;
}
以下是时序图:
可以看出在传输0x80时,无法有效传递,也就是说在应答信号时,将
OUT_AIP650E_SDA(1);
并没有收到该端口自动变低电平的信号,因此传输不成功,而中间这一段这么长的空闲,就是这段代码导致的
while(IO_SDA_PIN)
{
ucErrTime++;
if(ucErrTime>250)
{
f_AIP650E_SendStop();
return 1;
}
}
因为此时IO_SDA_PIN = 1;由于没有收到低电平信号,因此一直在执行While()里面的程序,直到最后达到最大时间,执行停止信号函数。
f_AIP650E_SendStop();
标红框的这一段是主循环的时间,跟我调用该函数位置有关。
3.OUT_AIP650E_SDA(0)的时序图
u8 f_AIP650E_Wait_Ack(void)
{
u8 ucErrTime=0;
AIP650E_SDA_INPUT;
OUT_AIP650E_SDA(0);
f_AIP650E_Delay();
OUT_AIP650E_SCL(1);
f_AIP650E_Delay();
while(IO_SDA_PIN)
{
ucErrTime++;
if(ucErrTime>250)
{
f_AIP650E_SendStop();
return 1;
}
}
OUT_AIP650E_SCL(0);
return 0;
}
可以看出与第一次的时序图完全一样,
总结
个人认为,在传输8为数据以后,在配置完SDA端口作为输入端口以后,需要手动的将SDA的端口电平置为“0”。避免由于上一个8为数据的最低位是1,硬件又不能将SDA端口自动置“0”,从而出现显示错误现象。(本次的第一个8位数据是0x6E,也就是0110 1110)因此可以看出最地位是0,不会影响下一次的8位数据传递,但是假如第二个8,也就是段选的时候数据为(0x81)那么传输的时候就会出现错误,因为SDA将会一直保持高电平,并不能满足ACK应答信号。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Liu_08290727/article/details/144895344