完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一句话梳理流程
stm32模拟硬件IIC时序,按照时序,EEPROM识别外部信号,完成对其的数据操作 目的: 使用32开发板软件模拟IIC实现对带有硬件IIC接口的eeprom完成写数据并将写入的数据读出来,内容显示到TFTLCD 硬件需求及连接: STM32精英开发板 板载的eeprom(容量256B) TFTLCD显示屏 为什么不使用硬件IIC 目前大部分 MCU 都带有 IIC 总线接口,但是这里我们不使用 STM32的硬件 IIC 来读写 24C02,而是通过软件模拟。STM32 的硬件 IIC 非常复杂,更重要的是不稳定,故不推荐使用。所以我们这里就通过模拟来实现了。有兴趣的读者可以研究一下 STM32的硬件 IIC。 IIC理解 它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
理解 我们stm32(mcu)定义为主机,eeprom定义为从机 很多读者梳理不清楚我们到底应该写哪些基本函数来完成从机的通信,我们想要写一个字节到从机里,首先有个开始信号,让外部通信的设备知道我们要开始传输数据了,这时候我们不用等待外部设备(从机)回复,因为这时候我们并未真正开始传输数据,也就不需要从机回复,接着把要写入的数据写入从机,不管从机接收到的是命令还是数据,统称为数据,都要对主机回复,反之,从机给主机发送数据,主机也要应答表示收到数据。 基础函数讲解 完成数据传输之前,我们需要模拟出stm32这一侧的时序,eeprom那一侧已经有硬件iic了,就不需要模拟。 理论不多说,直接上代码: 宏定义 前两行代码是寄存器的位操作,控制io口的输入输出,因为数据交换会时常改变数据的传输方向,如果经常使用GPIO_InitTypeDef*定义输入输出,很麻烦,所以使用位操作,方便快捷,这两个的效果是一样的,有兴趣的小伙伴可以去了解一下位操作。 #define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;} #define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;} #define IIC_SCL PBout(6) #define IIC_SDA PBout(7) #define READ_SDA PBin(7) 当然了,初始化IO口也是很有必要的: EEPROM初始化IO: void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //ʹÄÜGPIOBʱÖÓ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); } 初始化函数写完了,我们就可以利用此IO口来写时序了。 起始信号 void iic_start(void) { SDA_OUT();//mcu发出来的,所以是输出模式 IIC_SCL=1; IIC_SDA=1; delay_us(4);//延时 IIC_SDA=0; delay_us(4); IIC_SCL=0; } 看步骤都很简单,但是有的新手不明白,如果弄清楚了方向就清楚了,这个方向是从mcu–>从机,所以这是mcu的起始信号,又有的要问了,为什么我们不需要配置从机的起始信号,因为我们的从机不会主动发送信号,使用的也是硬件IIC,不需要我们配置 停止信号 主机发给从机,停止(结束)数据传输 void iic_stop(void) { SDA_OUT();//mcu发出来的,所以是输出模式 IIC_SCL=0; IIC_SDA=0; delay_us(4); IIC_SDA=1; IIC_SCL=1; delay_us(4); } mcu应答信号 mcu收到数据后应答给从机,也就是上面讲的 void iic_ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(4); IIC_SCL=1; delay_us(4); IIC_SCL=0; } mcu不应答信号 void iic_nack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; delay_us(4); IIC_SCL=1; delay_us(4); IIC_SCL=0; } mcu等待从机给回复: mcu发送数据到从机后,需要从机应答,在给定的时间内来允许从机应答,若未收到应答信号,则停止数据传输 uint8_t iic_wait_ack(void) { uint8_t time; SDA_IN(); IIC_SDA=1; delay_us(1); IIC_SCL=1; delay_us(4); while(READ_SDA) { time++; if(time>250) { iic_stop(); return 1; } } delay_us(4); IIC_SCL=0; return 0; } 接收到真实数据的数据接收方必须发送应答信号给发送方 这几个传输数据的逻辑函数写好了,就可以来传输真实数据的函数编写了 发送一个字节的时序函数: void iic_send_byte( uint8_t data) { uint8_t i; SDA_OUT(); IIC_SCL=0; for(i=0;i<8;i++) { IIC_SDA=(data&0x80)>>7; data<<=1; delay_us(4); IIC_SCL=1; delay_us(4); IIC_SCL=0; delay_us(4); } } 读一个字节的时序函数: uint8_t iic_read_byte( uint8_t i) { uint8_t j; uint8_t temp; SDA_IN(); for(j=0;j<8;j++) { IIC_SCL=0; delay_us(4); IIC_SCL=1; temp<<=1; if(READ_SDA) temp++; delay_us(4); } if(i) iic_ack(); else iic_nack(); return temp; } 基础函数写完了,我们并未写出传输到实际设备的函数,因为这里面包括器件的地址,数据,命令等等我们都没有涉及到现在,这只是为实际的数据传输做准备 想要操作EEPROM,我们就要利用上面的函数: 同样的,我们只是写了初始化函数,并未调用,所以我们要调用初始化函数 调用初始化函数: void _24c02_init(void) { IIC_Init(); } 在指定的地址上读住此地址的值(一个字节大小): 传入一个地址,便可得到此地址的值 uint8_t read_byte( uint16_t addr) { uint8_t ttpm; iic_start(); iic_send_byte(0xA0+((addr/256)<<1)); iic_wait_ack(); iic_send_byte(addr%256); iic_wait_ack(); iic_start(); iic_send_byte(0xA1); iic_wait_ack(); ttpm=iic_read_byte(0); iic_stop(); return ttpm; } 在指定的地址上写入指定的数据:参数是传入数据的地址和真实数据 void write_byte(uint16_t addr, uint8_t dat) { iic_start(); iic_send_byte(0xA0+((addr/256)<<1)); iic_wait_ack(); iic_send_byte(addr%256); iic_wait_ack(); iic_send_byte(dat); iic_wait_ack(); iic_stop(); delay_ms(10); } 向指定地址,写入长度为len字节的数据 void write_len_byte( uint16_t addr,uint16_t data, uint8_t len) { uint8_t k; for(k=0;k } 向指定地址开始,读出长度为len的值: uint8_t read_len_byte( uint16_t addr, uint8_t len) { uint8_t i; uint16_t temp; for(i=0;i temp<<=8; temp+=read_byte((addr+len-i-1)); } return temp; } 从上两个函数可以看出,低位地址存放的是数据字节高位,高位地址存放的是数据字节的低位 校验EEPROM是否可用: uint8_t _24c02_check(void) { uint8_t temp; temp=read_byte(255); if(temp==0X55)return 0; else { write_byte(255,0X55); temp=read_byte(255); if(temp==0X55)return 0; } return 1; } 初次读出的值应为0x55,如果不是,写入0x55,再读出,是否为0x55 指定地址,读出数据为len长度的数据存到指针里 void read_len_data_into_array( uint16_t device_add,uint8_t*a, uint8_t len) { uint8_t i; for(i=0;i *(a+i)=read_byte(device_add+i); } } 在指定地址,写入长度为len的数据: void write_len_data_into_device( uint16_t device_add,uint8_t*a, uint8_t len) { uint8_t i; for(i=0;i } 主函数main,直接调用: #include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "lcd.h" #include "usart.h" #include "iic.h" #include "24c02.h" const u8 TEXT_Buffer[]={"EEPROM TEST SUCCESS"}; #define SIZE sizeof(TEXT_Buffer) int main(void) { u8 key; u16 i=0; u8 datatemp[SIZE]; delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(115200); LCD_Init(); KEY_Init(); _24c02_init(); while(_24c02_check()) { LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!"); delay_ms(500); LCD_ShowString(30,150,200,16,16,"Please Check! "); delay_ms(500); } while(1) { key=KEY_Scan(0); if(key==KEY1_PRES) { LCD_Fill(0,170,239,319,WHITE); write_len_data_into_device(0,(u8*)TEXT_Buffer,SIZE); LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!"); } if(key==KEY0_PRES) { read_len_data_into_array(0,datatemp,SIZE); LCD_ShowString(30,170,200,16,16,"The Data Readed Is: "); LCD_ShowString(30,190,200,16,16,datatemp); } i++; delay_ms(10); } } 主函数就不讲解了,梳理主函数流程也是很有必要的 实验现象 下载完成过后,屏幕无显示,全白,如果不是全白,按照字符串提示修改自己的代码,按键按下,写入数据,按另一个个按键,读出数据,显示在显示屏上。 其他 本实验讲解了对原理的理解讲解,按照时序理解,未给出的时序,希望自行理解,希望对读者有所帮助,如果有什么错误与建议,请及时沟通交流!谢谢 |
|
|
|
只有小组成员才能发言,加入小组>>
3314 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9059 浏览 16 评论
4088 浏览 18 评论
1178浏览 3评论
605浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
599浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 05:42 , Processed in 1.097544 second(s), Total 48, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号