收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
首先主机发送一个起始位,然后在发送从机的地址0x00和写标志位0,一共是8位。发送这8位之后,主机等待从机的响应,如过从机发送的是应答信号,主机就继续向从机发送一个字节的数据,同理再一次等待从机的响应,主机收到响应之后如果还有数据要发就继续发送第二段数据等待响应…直到发送完成;
写所用到的函数有:
1.void SMBus_StartBit(void);----主机发送一个起始位
2. u8 SMBus_ SendByte (u8 ack_nack)— 主机发送从机的地址和写标志位
3. SMBus_ReceiveBit(ack_nack);-- 从机发送的是应答信号
4. u8 SMBus_SendByte(u8 ack_nack)—主机发送从机的一个字节的数据
5.void SMBus_StopBit(void)-- ----主机发送一个停止位
2.读时序
首先主机发送一个起始位,然后在发送从机的地址0x00和读标志位1,一共是8位。发送这8位之后,主机等待从机的响应,如过从机发送的是应答信号,从机就向主机发送一个字节的数据。读时序就是主机从从机读数据,反过来就是从机向主机发送数据,同理,从机在发送完一个字节的数据之后也要向主机询问是否继续发送,如果主机让继续发送也就是发送了应答信号,那么从机就继续发送数据,每次发送完之后都要询问是否要继续发送,直到主机发送了非应答信号,从机才停止发送数据,最后主机再发送一个停止信号即可。
读所用到的函数有:
1.void SMBus_StartBit(void);—主机发送一个起始位
2. u8 SMBus_ SendByte (u8 ack_nack)—主机发送从机的地址和写标志位
3. SMBus_ReceiveBit(ack_nack);-- 从机发送的是应答信号
4. u8 SMBus_ReceiveByte (u8 ack_nack)–从机向主机发送的一个字节的数据
5.void SMBus_StopBit(void)-- ----主机发送一个停止位
3.通信过程
- 1.起始信号–在时钟线SCL高电平期间数据线SDA发生下降沿跳变产生起始信号
- 2.应答信号–在时钟线SCL为高电平期间数据线SDA保持低电平为应答信号
- 3.非应答信号–在时钟线SCL为高电平期间数据线SDA保持高电平为非应答信号
- 4.结束信号–在时钟线SCL高电平期间数据线SDA发生上升沿跳变产生停止信号
- 5.数据信号–在数据传输期间,时钟线 SCL 为高电平期间,如果数据线 SDA 为高电平则代表二进制1,同理,时钟线 SCL 为高电平期间,如果数据线 SDA 为低电平则代表二进制 0。
- 6.上面1号框是SDA 数据有效期,2号框是数据改变期。
五、程序编写
1.起始信号与停止信号
void SMBus\_StartBit(void)
{
SMBUS\_SDA\_H(); // 首先拉高数据线
SMBus\_Delay(5); // 延时几微妙
SMBUS\_SCK\_H(); // 拉高时钟线
SMBus\_Delay(5); // 延时几微妙
SMBUS\_SDA\_L(); // 拉低数据线
SMBus\_Delay(5); // 延时几微妙
//在SCK=1时,检测到SDA由1到0表示通信开始(下降沿)
SMBUS\_SCK\_L(); // 拉低时钟线
SMBus\_Delay(5); // 延时几微妙
}
void SMBus\_StopBit(void)
{
SMBUS\_SCK\_L(); // 拉低时钟线
SMBus\_Delay(5); // 延时几微妙
SMBUS\_SDA\_L(); // 拉低数据线
SMBus\_Delay(5); // 延时几微妙
SMBUS\_SCK\_H(); // 拉高时钟线
SMBus\_Delay(5); // 延时几微妙
SMBUS\_SDA\_H(); // 拉高数据线
}
2.发送一个字节
u8 SMBus\_SendByte(u8 Tx_buffer)
{
u8 Bit_counter;
u8 Ack_bit;
u8 bit_out;
for(Bit_counter=8; Bit_counter; Bit_counter--)
{
if (Tx_buffer&0x80)//如果最高位为1
{
bit_out=1; // 把最高位置1
}
else //如果最高位为0
{
bit_out=0; // 把最高位置0
}
SMBus\_SendBit(bit_out); // 把最高位发送出去
Tx_buffer<<=1;// 左移一位把最高位移出去等待下一个最高位,循环8次,每次都发最高位,就可把一个字节发出去了
}
Ack_bit=SMBus\_ReceiveBit(); // Get acknowledgment bit
return Ack_bit;
}
发送一个字节也就是8个bit位,我们的做法就是循环8次,每次将最高位发送出去。如果最高位为1,我们将这一个字节Tx_buffer和0x80(10000000)进行"与运算",把最高位置为1。如果最高位为0,就把最高位置为0,再通过 SMBus_SendBit(bit_out); 把最高位发送出去,之后再通过Tx_buffer<<=1;左移一位把最高位移出去等待下一个最高位,循环8次,每次都发最高位,就可把一个字节发出去了。这里是SMBus发送一个字节,我们知道在从机发送完一个字节之后,主机要返回一个应答信号告诉从机是否继续发送下一个字节,所以这里我们 使用Ack_bit=SMBus_ReceiveBit();这条语句来告诉从机书否还要继续发送下一个字节,如果返回的是0就继续发送,如果返回的是1就停止发送。
3.接收一个字节
u8 SMBus\_ReceiveByte(u8 ack_nack)
{
u8 RX_buffer;
u8 Bit_Counter;
for(Bit_Counter=8; Bit_Counter; Bit_Counter--)
{
if(SMBus\_ReceiveBit())// Get a bit from the SDA line
{
RX_buffer <<= 1;// If the bit is HIGH save 1 in RX\_buffer
RX_buffer |=0x01;//如果Ack\_bit=1,把收到应答信号1与0000 0001 进行或运算,确保为1
}
else
{
RX_buffer <<= 1;// If the bit is LOW save 0 in RX\_buffer
RX_buffer &=0xfe;//如果Ack\_bit=1,把收到应答信号0与1111 1110 进行与运算,确保为0
}
}
SMBus\_SendBit(ack_nack);//把应答信号发出去,如果0,就进行下一次通信,如果为1,就拜拜了。
return RX_buffer;
}
从SMBus上接收一个字节也就是8位,我们也是用一个for循环将8各一次接受过来。首先问我们通过if函数来判断SMBus_ReceiveBit()是否是收到了应答信号,如果收到了的应答信号也就是1,我们就将收到的数据左移1位RX_buffer <<= 1;如果左移一位之后空出的那一位数据位1然后就与0x01也就是0000 0001 进行"或运算",确保为1。如果左移一位之后空出的那一位数据位0然后就与0xfe也就是1111 1110 进行"或运算",确保为0。最后SMBus把应答信号发出去,如果0,就进行下一次通信,如果为1,就拜拜了,就不接受数据了。
4.数据校验
u8 PEC\_Calculation(u8 pec[])
{
u8 crc[6];//存放多项式
u8 BitPosition=47;//存放所有数据最高位,6\*8=48 最高位就是47位
u8 shift;
u8 i;
u8 j;
u8 temp;
do
{ //Load pattern value 0x00 00 00 00 01 07
crc[5]=0;
crc[4]=0;
crc[3]=0;
crc[2]=0;
crc[1]=0x01;
crc[0]=0x07;
BitPosition=47;
shift=0;
i=5;
j=0;
while((pec[i]&(0x80>>j))==0 && i>0)
{
BitPosition--;
if(j<7)
{
j++;
}
else
{
j=0x00;
i--;
}
}
shift=BitPosition-8;
while(shift)
{
for(i=5; i<0xFF; i--)
{
if((crc[i-1]&0x80) && (i>0))
{
temp=1;
}
else
{
temp=0;
}
crc[i]<<=1;
crc[i]+=temp;
}
shift--;
}
for(i=0; i<=5; i++)
{
pec[i] ^=crc[i];
}
}
while(BitPosition>8);
return pec[0];
}
这个数据校验是很重要的,目的就是来判断检测你采集的数据是否是是正确的。
也就是我们程序会把PEC的数据通过SA_W、Command、SA_R把LSByte、MSByte读出来。然后我们自己再写一个校验的函数来判断读到的PEC数据是否正确,如果正确了才能进行下一步的判断,如果不正确的话就继续读,直到正确为止。如何才能知道自己读到的数据是否正确呢?这就需要自己单独建立一个C工程,把这个函数u8 PEC_Calculation(u8 pec[])放到里面运行一遍,看看自己输入的数据时候跟自己要得到数据数据是否一样就可以了。也就是把0x00、0x3a、0xd2、0xb5、0x07、0xb4放到这个函数运行,最终返回出来的数据是否是0x30就可以了,如果是就说明数据校验正确,如果不是就需要该函数,至于为啥返回的是0x30请看上面的时序表。
5.读取温度函数
u16 SMBus\_ReadMemory(u8 slaveAddress, u8 command)
{
u16 data;
u8 Pec;
u8 DataL=0;
u8 DataH=0;
u8 arr[6];
u8 PecReg;
u8 ErrorCounter;
ErrorCounter=0x00;// Initialising of ErrorCounter
slaveAddress <<= 1; //2-7位表示从机地址 从机地址左移一位,把读写位空出来
do
{
repeat:
SMBus\_StopBit();
--ErrorCounter;
if(!ErrorCounter) //ErrorCounter=0?
{
break; //如果为0就跳出do-while{}循环
}
SMBus\_StartBit();
if(SMBus\_SendByte(slaveAddress))//发送从机地址最低位Wr=0表示接下来写命令
{
goto repeat;
}
if(SMBus\_SendByte(command))//发送命令
{
goto repeat;
}
SMBus\_StartBit();
if(SMBus\_SendByte(slaveAddress+1)) //发送从机地址+1最低位Rd=1表示接下来读数据
{
goto repeat;
}
DataL = SMBus\_ReceiveByte(ACK); //读低位数据保存到DataL
DataH = SMBus\_ReceiveByte(ACK); //读高位数据保存到DataH
Pec = SMBus\_ReceiveByte(NACK); //读校验数据保存到Pec
SMBus\_StopBit();
arr[5] = slaveAddress;
arr[4] = command;
arr[3] = slaveAddress+1;
arr[2] = DataL;
arr[1] = DataH;
arr[0] = 0;
PecReg=PEC\_Calculation(arr);//Calculate CRC 数据校验
}
while(PecReg != Pec);
data = (DataH<<8) | DataL;
return data;
}
这个函数的输入参数就IIC设备的从机地址和command寄存器地址。首先从机地址左移一位,把读写位空出来,因为不知道最开始是啥状态,我们就需要发送一个停止信号,因为ErrorCounter=0x00;那么进行"–"操作之后就不等于0,就进行下面的操作。接下来就发送起始信号,发送从机设备地址,如果发送的从机地址正确,就接着发送操作从机地址的command这个地址,因为这里报存着温度数据。然后重新发起一个起始信号,开始读数据,把温度数据的低位DataL高位DataH 和PEC数据读出来,再进行PEC数据校验,判断读到的PEC数据和校验得到的PEC数据是否相等,相等的话就跳出循环,通过将高位数据左移8位再与低8位进行按位或就得到了最终的数据data。
6.得到最终温度值
float SMBus\_ReadTemp(void)
{
float temp;
temp = SMBus\_ReadMemory(0x00, 0x07)\*0.02-273.15;
return temp;
}
通过数据手册我们知道将最终读取的数据*0.02-273.15就会得到最终的温度实际值,通过串口打印或者oled显示就可以得到传感器读取的温度了。
六、CRC8校验原理
1.模2除法
模2除法与算术除法类似,但每一位除的结果不影响其它位,即不向上一位借位,所以实际上就是异或。在循环冗余校验码(CRC)的计算中有应用到模2除法。CRC校验中有两个关键点,一是预先确定一个发送端和接收端都用来作为除数的二进制比特串(或多项式),可以随机选择,也可以使用国际标准,但是最高位和最低位必须为1;二是把原始帧与上面计算出的除数进行模2除法运算,计算出CRC码。
2.具体步骤
- 选择合适的多项式,确定除数。
- 看选定多项式的二进制位数,然后将要发送的数据上面加上这个位数1位的0,然后用得到的数据以模2除法的方式除上面确定的除数,得到的余数就是该数的CRC校验码。注意,余数的位数一定只比除数位数少一位,也就是CRC校验码位数比除数位数少一位,如果前面位是0也不能省略。
3.实例1
现假设我们使用的多项式为:G(X) =X^ 8 + X^ 2+X^ 1+1,要求出0x1A的CRC8校验码。下面是具体的计算过程:
1、 将多项式转化为二进制序列,由G(X) = X^ 8 + X^ 2+X^ 1+1可知二进制一种有9位,第8位、第2位、第1位和第0位分别为1,则序列为100000111。
2、原来要计算的数据为1 1010,多项式的最高次为8,则在数据的后面加上8位0,数据变为110100000 0000,然后使用模2除法除以除数100000111,最终得到的除不尽的余数,变为我们要求的CRC8结果。
3、最后除不尽的余数为0x46,所以0x1A按多项式G(X) = X8+X2+X+1计算得到的CRC8码为0x46。
4.示例2
也就是求0xb4 0x07 0xb5 0xd2 0x3a 的CRC8校验码是否是0x30
- 将多项式转化为二进制序列,由G(X) = X8+X2+X^1+1可知二进制一种有9位,第8位、第2位、第1位和第0位分别为1,则序列为100000111。
- 原来要计算的数据为b4 07 b5 d2 3a转换为2进制就是
1011010000000111101101011101001000111010
,多项式的最高次为8,则在数据的后面加上8位0,数据变为
101101000000011110110101110100100011101000000000,然后使用模2除法除以除数100000111,最终得到的除不尽的余数,变为我们要求的CRC8结果。
5.读取温度函数
u16 SMBus\_ReadMemory(u8 slaveAddress, u8 command)
{
u16 data;
u8 Pec;
u8 DataL=0;
u8 DataH=0;
u8 arr[6];
u8 PecReg;
u8 ErrorCounter;
ErrorCounter=0x00;// Initialising of ErrorCounter
slaveAddress <<= 1; //2-7位表示从机地址 从机地址左移一位,把读写位空出来
do
{
repeat:
SMBus\_StopBit();
--ErrorCounter;
if(!ErrorCounter) //ErrorCounter=0?
{
break; //如果为0就跳出do-while{}循环
}
SMBus\_StartBit();
if(SMBus\_SendByte(slaveAddress))//发送从机地址最低位Wr=0表示接下来写命令
{
goto repeat;
}
if(SMBus\_SendByte(command))//发送命令
{
goto repeat;
}
SMBus\_StartBit();
if(SMBus\_SendByte(slaveAddress+1)) //发送从机地址+1最低位Rd=1表示接下来读数据
{
goto repeat;
}
DataL = SMBus\_ReceiveByte(ACK); //读低位数据保存到DataL
DataH = SMBus\_ReceiveByte(ACK); //读高位数据保存到DataH
![img](https://img-blog.csdnimg.cn/img_convert/ce974f5ffdbe8ea552a3575b6d30accf.png)
![img](https://img-blog.csdnimg.cn/img_convert/34e9279dec15ce7924e7306aa97aaef4.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
SMBus\_ReceiveByte(ACK); //读高位数据保存到DataH
[外链图片转存中...(img-Bcvmtqyo-1715802307460)]
[外链图片转存中...(img-BaRMdp9P-1715802307460)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**