完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
I2C向EEPROM写入一字节数据(I2C硬件)
1 实现功能 本实验所要完成的任务是通过I2C向EEPROM中发送一个字节的数据。 并且能够通过串口调试助手查看到发送状态与现实错误代码。 2 硬件设计 本实验采用的开发板为“正点原子”探索者F4开发板,核心芯片为F407ZGT6。 使用到的外设及硬件为:USART1,I2C1,EEPROM。 USART1:PA9(T)—》RXE;PA10(R) —》TXE,将引脚使用跳线帽相连接即可。 3 软件设计流程
宏定义及函数申明 //定义一个超时常数 #define TIME_OUT 0x000FFFFF uint32_t count_wait = TIME_OUT; //申明故障代码返回函数 uint8_t Error_Back(uint8_t error_code); 初始化I2C void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能GPIOB时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //使能I2C1时钟 GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1); GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_I2C1); //GPIOB8初始化SCL GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //普通输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //开漏输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 //GPIOB9初始化SDA GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //普通输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //开漏输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 //初始化I2C结构体 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能ask响应 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit ; //设定7为地址 I2C_InitStructure.I2C_ClockSpeed = 400000; //设置时钟速度 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2 ; //指定时钟占空比1/2与9/16选择 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //设置为I2C模式 I2C_InitStructure.I2C_OwnAddress1 = 0x78; //指定自身的I2C设备地址。另一种说法:作为主机时可以不用写? I2C_Init(I2C1,&I2C_InitStructure); //初始化结构体 I2C_Cmd(I2C1,ENABLE); //I2C使能 } EEPROM写入一个字节函数 //addr:是要写入存储单元的地址 //date:是要写入的数据 uint8_t EEPROM_Byte_Write(uint8_t addr, uint8_t date) { //产生起始条件 I2C_GenerateSTART(I2C1,ENABLE); //重置count_wait count_wait = TIME_OUT; //等待EV5事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ) { count_wait--; if(count_wait == 0) { //表示程序执行卡在EV5,发送开始信号阶段 return Error_Back(1); } } //======================================================================================== //要发送的EEPROM设别地址 高四位:1010固定 低四位:A2 A1 A0 R/W 0 0 0 0 1010 0000 = 0xa0 I2C_Send7bitAddress(I2C1,0xa0,I2C_Direction_Transmitter); //重置count_wait count_wait = TIME_OUT; //等待EV6事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(2); } } //======================================================================================== //发送要写入的存储单元的地址 I2C_SendData(I2C1,addr); //重置count_wait count_wait = TIME_OUT; //等待EV8_2事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(3); } } //======================================================================================== //发送要写入的数据 I2C_SendData(I2C1,date); //重置count_wait count_wait = TIME_OUT; //等待EV8_2事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(4); } } //======================================================================================== //产生结束信号 I2C_GenerateSTOP(I2C1,ENABLE); //表示程序执行正常 return 0; } 随机读取一个字节函数 //addr:是要读取存储单元的地址 //date:用来存储 读取到的数据 的指针 //returen:表示正常,非0为失败 uint8_t EEPROM_Random_Read(uint8_t addr, uint8_t *date) { //======================================================================================== //产生第一次起始条件 I2C_GenerateSTART(I2C1,ENABLE); //重置count_wait count_wait = TIME_OUT; //等待EV5事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(5);//表示程序执行卡在EV5,发送开始信号阶段 } } //==========================================写方向=========================================== //要发送的EEPROM设别地址 高四位:1010固定 低四位:A2 A1 A0 R/W 0 0 0 0 1010 0001 = 0xa1 写方向 I2C_Send7bitAddress(I2C1,0xa0,I2C_Direction_Transmitter); //重置count_wait count_wait = TIME_OUT; //等待EV6事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(6); } } //======================================================================================== //发送要写入的存储单元的地址 I2C_SendData(I2C1,addr); //重置count_wait count_wait = TIME_OUT; //等待EV8_2事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(7); } } //======================================================================================== //产生第二次起始信号 //产生起始条件 I2C_GenerateSTART(I2C1,ENABLE); //重置count_wait count_wait = TIME_OUT; //等待EV5事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(8);//表示程序执行卡在EV5,发送开始信号阶段 } } //============================================读方向========================================= //发送要读取的EEPROM设别地址 高四位:1010固定 低四位:A2 A1 A0 R/W 0 0 0 0 1010 0000 = 0xa0 读方向 I2C_Send7bitAddress(I2C1,0xa0,I2C_Direction_Receiver); //重置count_wait count_wait = TIME_OUT; //等待EV6事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(9); } } //做出非应答信号 这个函数要放在receivedata前面,否则在接受数据的时候,会多接收一个数据才结束 I2C_AcknowledgeConfig(I2C1,DISABLE); //重置count_wait count_wait = TIME_OUT; //等待EV8_2事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(10); } } //接收读取到的数据 *date = I2C_ReceiveData(I2C1); //产生结束信号 I2C_GenerateSTOP(I2C1,ENABLE); //表示程序执行正常 return 0; } 等待EEPROM内部写入操作完成函数。 //等待ERROR内部写入操作完成 uint8_t Wait_For_Standby(void) { uint32_t check_count = 0xFFFFF; while(check_count--) { //产生起始条件 I2C_GenerateSTART(I2C1,ENABLE); //重置count_wait count_wait = TIME_OUT; //等待EV5事件,直到成功 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ) { count_wait--; if(count_wait == 0) { return Error_Back(11);//表示程序执行卡在EV5,发送开始信号阶段 } } //要发送的EEPROM设别地址 高四位:1010固定 低四位:A2 A1 A0 R/W 0 0 0 0 1010 0001 = 0xa1 写方向 I2C_Send7bitAddress(I2C1,0xa0,I2C_Direction_Transmitter); //重置count_wait count_wait = TIME_OUT; //等待EV6事件,直到成功 while(count_wait--) { //若检测到响应,说明内部写时序完成,跳出循环 if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == SUCCESS) { //产生结束信号 I2C_GenerateSTOP(I2C1,ENABLE); return 0; } } } //产生结束信号 I2C_GenerateSTOP(I2C1,ENABLE); //表示程序执行正常 return 1; } 错误代码返回函数 uint8_t Error_Back(uint8_t error_code) { printf("rn I2C ERROR OCCOR! THE ERROR NUMBER IS %d!rn",error_code); return error_code; } 主函数 int main(void) { uint8_t data; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(115200); //初始化串口波特率为115200 LED_Init(); //初始化LED LCD_Init(); //LCD初始化 KEY_Init(); //按键初始化 IIC_Init(); //I2C初始化 EEPROM_Byte_Write(0x05, 0x22); //向EEPROM写入数据 Wait_For_Standby(); //等待传输完成 EEPROM_Random_Read(0x05,&data); //随机读取数据 printf("rnox%xrn",data); } 5 效果展示
这个实验不难,主要是熟练以下寄存器的使用已经一个设计的流程,其次,代码功能的优化也是非常重要的,在文中,错误代码的显示以及程序超时这两个功能(从野火那儿学习来的)都是属于代码优化。所以我们要放宽视野,多学学人家良好的编程习惯。谢谢!请各位大佬不吝赐教! |
|
|
|
只有小组成员才能发言,加入小组>>
3309 浏览 9 评论
2990 浏览 16 评论
3490 浏览 1 评论
9052 浏览 16 评论
4085 浏览 18 评论
1171浏览 3评论
602浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
594浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2332浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1894浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 03:41 , Processed in 1.106971 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号