历史上的今天
今天是:2024年10月16日(星期三)
2018年10月16日 | stm32之TFT触摸屏(ILI9320)(2):由触摸屏写入EEPROM
2018-10-16 来源:eefocus
程序来源是电阻触摸屏的触摸显示实验。TFT触摸屏呢,不仅仅是ILI9320这一个芯片,还涉及到两个,一个是ADS7846,一个是AT24CXX。这两个都分别是什么东西呢,ADS7846是TFT控制器,它的主要作用就是在按压之后,把这个值通过ADC进行模数转换,这个控制器是TFT屏幕必备的,当然可以有很多型号,这个ADS7846只是其中一种;这个AT24CXX则是EEPROM,XX不是真的字母X,而是省略了数字,比如AT24C02,这个是个2K的EEPROM,我们这里用的也是这款,它能干什么呢,存储数据,通过ADC得到的值需要变换为屏幕坐标什么的,这个EEPROM就可以存储这个基准值。
ADS7846的操作是通过SPI进行的,之前讲SPI移植的时候实际讲的比较透彻了,操作也比较简单,看下程序就能懂了。AT24CXX则是通过IIC进行的,所以讲下。
SPI和IIC有什么不同呢,我的感觉主要是三点:1.二者的协议方式不同,就是起始结束数据接收什么的这是不同的。2.IIC是单向的,同一时刻只能有一个方向,而SPI由于有MOSI和MISO两个线,所以是双工的,而且IIC还有设备地址这种机制,可以当总线。3.二者的速度差别也很大,SPI的速度要比IIC快很多。
stm32的数据手册中详细介绍了SPI和IIC的各种模式以及寄存器,但是实际操作的时候不需要那么麻烦,因为那个是硬件SPI和硬件IIC,我们在正常使用的使用模拟SPI和模拟IIC就好,方便快捷。
首先讲下最简单的IIC协议:
1.在I2C总线传输过程中,将两种特定的情况定义为开始和停止条件:当SCL保持“高”时,SDA由“高”变为“低”为开始条件;当SCL保持“高”且SDA由“低”变为“高”时为停止条件。开始和停止条件均由主控制器产生。数据传送具有应答是必须的。
2.与应答对应的时钟脉冲由主控制器产生,发送器在应答期间必须下拉SDA线。当寻址的被控器件不能应答时,数据保持为高并使主控器产生停止条件而终止传输。在传输的过程中,在用到主控接收器的情况下,主控接收器必须发出一数据结束信号给被控发送器,从而使被控发送器释放数据线,以允许主控器产生停止条件。
3.I2C总线在开始条件后的首字节决定哪个被控器将被主控器选择,例外的是“通用访问”地址,它可以在所有期间寻址。当主控器输出一地址时,系统中的每一器件都将开始条件后的前7位地址和自己的地址进行比较。如果相同,该器件即认为自己被主控器寻址,而作为被控接收器或被控发送器则取决于R/W位。
有上面这三点的知识就足够操作模拟IIC了
再看下EEPROM的硬件连接,在使用板子的数据手册里,如下图

可以看到,IIC的时钟和数据引脚PB10和PB11,这里在使用的时候是需要对引脚进行初始化的。看下IIC写数据的函数就应该一目了然了。
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
IIC_Start();
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0);
IIC_Wait_Ack();
}else
{
IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));
}
IIC_Send_Byte(WriteAddr%6);
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite);
IIC_Wait_Ack();
IIC_Stop();
delay_ms(10);
}
IIC_Start()的作用, IIC_SDA=1,这里是PB11拉高,IIC_SCL=1,这里是PB10拉高,延时后IIC_SDA=0;,说明在时钟线为高,SDA由高变为低,即为开始条件,接着IIC_SCL=0,即时钟线拉低,准备发送或接收数据。
通过IIC_Send_Byte进行指令的写入,每一次传输都传输最高位,通过SCL的拉高拉低实现1bit的发送,这个函数不细讲了,就是根据时序,拉高拉低就可以。
为什么IIC_Send_Byte发送的指令是0XA0呢,还是要看AT24C的数据手册,芯片用的是EEPROM,AT24C02的意思就是它是2K的
DEVICE/PAGE ADDRESSES (A2, A1, A0): The A2, A1 and A0 pins are device
address inputs that are hard wired for the AT24C01A and the AT24C02. As many as
eight 1K/2K devices may be addressed on a single bus system
这段是说呢,因为它小,所以在一个总线系统内可以搞个片选,空了三个引脚,就是可以连8个,16K那个就不用片选引脚。
再看下AT24C的数据手册,关于器件地址和字写入那里,


上面这个呢是Device address的图,说明了机器地址的结构,2K的EEPROM高4位为0xA0 ,下面这个图不是帧结构而是SDA上的数据,可以看到,发送期间地址--应答---字地址--应答----数据--应答,这么个方式实现了字的写入,也就是写入了机器地址,等个应答,这么个意思,这里都是0,说明这个EEPROM就一片。
发送函数的下一个是IIC_Wait_Ack()。先配置PB11上拉/下拉输入模式,使SCK和SDA均为高,超时返回接收失败,未超时,拉低时钟线,这里的应答,与EEPROM的机制有关,查询AT24C的数据手册,有这样一段A write operation requires an 8-bit data word address following the device address word and acknowledgment. Upon receipt of this address, the EEPROM will again respond with a zero and then clock in the first 8-bit data word. Following receipt of the 8-bit data word, the EEPROM will output a zero and the addressing device, such as a microcontroller, must terminate the write sequence with a stop condition. 就是说接收到8位数据之后会返回一个0值,才会确认数据接收成功,后文的发送应答函数IIC_Ack就是发送一个0的意思。
回到函数AT24CXX_WriteOneByte中,WriteAddr%6和WriteAddr/256,拿个数试下就知道,这个一个是取高8位和低8位的操作,跟>>8一样,这里写入字的地址写成16位的应该是为了更好的可移植性,c02是只有8位数据地址的
AT24C01A, 1K SERIAL EEPROM: Internally organized with 16 pages of 8 bytes each,
the 1K requires a 7-bit data word address for random word addressing.
AT24C02, 2K SERIAL EEPROM: Internally organized with 32 pages of 8 bytes each,
The 2K requires an 8-bit data word address for random word addressing.
The data word address lower three (1K/2K) or four (4K, 8K, 16K) bits are internally incremented following the receipt of each data word. The higher data word address bits are not incremented, retaining the memory page row location.
把程序中的高8位那段去掉,在屏幕校准也是完全没问题的,有可能是数据手册没写特别具体.
这段就是通过IIC向EEPROM写入了需要存储的数据,之后屏幕里的相关函数中就没有IIC的相关操作了,这里注意一点,AT24CXX数据手册中SDA line示意非常重要,看懂这个SDA line,就可以模拟IIC进行数据的传输了。
史海拾趣
|
4.1.1 符号定义(Symbol Definition)伪指令 符号定义伪指令用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等操作。常见的符号定义伪指令有如下几种: — 用于定义全局变量的GBLA、GBLL和GBLS。 — 用于定义局部变量的LCLA、LCLL ...… 查看全部问答> |
|
新手学习uboot,对于地址重定位的问题始终没有搞明白,请高手指点 Q1:start.s最初是在0x0000开始的地址处开始执行,中间有个过程是把自己以及uboot的其他代码搬移到0x3ff8 0000的位置,可是程序是怎么跳转到0x3ff8000处(或者所在的ram中)运行 ...… 查看全部问答> |
|
(一) 求#define fun(a,b) a+b 问 30/fun(5,6)*fun(8,9)运算结果 34 ? (二)写出4种BOOL值 char* p1=\"abcd\"; char p2[]=\"abcd\"; const char *p3=\"abcd\"; ...… 查看全部问答> |
|
我把初始化捕获和中断函数贴出来。。 大侠帮我看看有没问题啊。。。。?在P1,1接一个3V方波,就是不能进入捕获中断(定时器溢出中断能进入) void InitCaputor() { //IO初始化 P1DIR &= ~BIT1; &nb ...… 查看全部问答> |




