提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
STM32F103ZET6学习笔记
I2C读写EEPROM,写入long double类型,野火教程里写了通过(void*)实现long double类型数据的读/写。本篇用于分析这样写的理由
主函数
long double DATA_WRITE_32_BUFFER[4] ={12.56,77.89,-11.5,0.01};
long double DATA_READ_32_BUFFER[4] ={0};
#define Add32 0
int main(void)
{
USART1_INIT();
AT24CXX_Init();
while(1)
{
if(!AT24CXX_Check())
{
printf("\r\nAT24C02存在,且标志位为:0x%x\r\n",AT24CXX_ReadLenByte(255,1));
printf("\r\n现在开始写入数据!\r\n");
AT24CXX_Write(Add32,(void*)DATA_WRITE_32_BUFFER,sizeof(DATA_WRITE_32_BUFFER));
printf("\r\n数据写入完成!\r\n");
printf("\r\n开始读出数据!\r\n");
AT24CXX_Read(Add32,(void*)DATA_READ_32_BUFFER,sizeof(DATA_READ_32_BUFFER));
for(num = 0;num<4 ;num++)
{
printf("\r\DATA_READ_32_BUFFER[%d] = %Lf\r\n",num,DATA_READ_32_BUFFER[num]);
}
printf("\r\n输出已结束!\r\n");
}
else
{
printf("这是第一次运行程序,标志位已写入,请按复位键重新开始!");
}
while(1);
}
}
写函数
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
while(NumToWrite--)
{
AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
WriteAddr++;
pBuffer++;
}
}
读函数
//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
while(NumToRead)
{
*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
NumToRead--;
}
}
以上写入和读取代码来自正点原子
void*作用
下面这篇博客详细的讲述了各类型指针的本质区别:不同指针的跳跃力不同
https://blog.csdn.net/yangbodong22011/article/details/53224856
long double BUFFER[] = {255.63,553.98};
long double类型占用8个字节(STM32中),那么数组BUFFER中,每一个数据都占据8个字节。那么这个BUUFER一共占据16个字节。
但EEPROM一次只能写入1个字节,然后接下来的数据就要放到下一个地址,所以需要8个地址才能写完。
AT24CXX_Write(Add32,(void*)DATA_WRITE_32_BUFFER,sizeof(DATA_WRITE_32_BUFFER));
但是写完一个字节,地址会+1,这时候,指针会直接跳8个字节,指向下一个数据的地址,因为long double类型的数据就是8个字节,所以第一个数据仅仅写了1/8,就跳过了。
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
while(NumToWrite--)
{
AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
WriteAddr++;
pBuffer++;
}
所以我们希望,在写入数据的时候,能把指针类型改变一下,变成一次仅跳过一个字节AT24CXX_Write里的是u8*
,这样每次地址+1,会继续读取第一个数据的第二个字节,一直读完8个字节,这样我们一个8个字节的数据就存在EEPROM的8个地址内了。
同时如果我们直接将long double类型的数组传进去**,会报错,指针类型不匹配**
所以我们可以直接将long double类型的数组强制转换为(void*)
,void*
可以兼容不同类型的指针,这样传进去后,经过u8
转换为跳跃力为1个字节的指针,这样就可以读取每一个字节,不会跳过某些字节。
读数据时也一样,我们是一个字节一个字节的读出来的,同时放到我们所定义的数组里,由于我们的数组时是long double类型的,所以输出时,会按8个字节为一个数据来输出。
AT24CXX_Read(Add32,(void*)DATA_READ_32_BUFFER,sizeof(DATA_READ_32_BUFFER));
//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
while(NumToRead)
{
*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
NumToRead--;
}
}
这样就实现了多字节数据的写入与读取.
总结
本质上就是进行了**数据格式转换,**因为写入的时候指针为u8
类型,若传入其他类型指针,一定会报错,所以void*
的兼容性很好的处理了这个问题。所以我们也可以把void*
变为u8*
,这样也是可以的,但是void*
更加具有通用性。
void*可以解决第一和第二步
- 写入的时候按照一个字节一个字节的写入
- 读的时候一个字节一个字节读出
- printf时我们用我们想要的数据格式来输出,比如8个字节、4个字节等等