基于STM8的IIC协议--协议篇

发布者:Mingyue1314最新更新时间:2019-12-04 来源: eefocus关键字:STM8  IIC协议  协议 手机看文章 扫描二维码
随时随地手机看文章

1. 综述


  I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。


  它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU和被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。但在STM8中,400kHZ已经是最快速度了。


2.关于STM8S103手册的I2C简介

芯片手册中只对I2C的特点进行了简单的讲解,但并未深入解析其中的过程。


3. I2C详细解析


  I2C总共由五个核心函数,分别为:①起始信号②停止信号③应答信号④发送数据⑤接收数据,通过这五个核心基本函数就能于大多数的传感进行通信了。


3.1 起始信号


  当SCL为高电平期间,SDA由高电平到低电平的跳变过程;起始信号是一种电平跳变时序信号,而不是一个电平信号,如图虚线框所示。


3.2 停止信号


  当SCL为高电平期间,SDA由低电平到高电平的跳变过程;停止信号也是一种电平跳变时序信号,而不是一个电平信号,如图虚线框所示。

3.3 应答信号


  I2C的数据字节定义为8位长,对于发送端每发送1个字节后,需要将数据线(SDA)释放,由接收端反馈一个应答信号(ACK)。应答信号为低电平时,则将其规定为有效信号(ACK简称应答位),表示接收端已经成功接收了该字节;应答位为高电平时,规定为非应答位(NACK),一般表示接收端没有成功接收该字节。


  对于反馈有效应答位ACK的要求是,接收端在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收端是主机,则在它接收到最后一个字节后,发送一个NACK信号,以通知发送端结束数据发送,并释放SDA线,以便主机接收端发送一个停止信号。

3.4 发送数据


  在发送起始信号后开始通信,主机发送一个8位数据。然后,主机释放SDA线并等待从从机发出得确认信号(ACK)。详细过程请看4.3.7代码示例。


3.5 接收数据


  在发送起始信号后开始通信,主机发送一个8位数据。然后,从机收到数据返回一个确认信号(ACK)给主机,这时候主机才开始接收数据,待主机接收数据完成后,发送一个NACK信号给从机,以通知接收端结束数据接收。详细过程请看4.3.8代码示例。


3.6 数据有效性


  I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。


3.7 I2C通信总过程 

4. 例程


4.1 编译环境:


  我的编译环境是IAR,这款软件是现在STM8的主流平台,比较推荐。不过我打算等到STCubeMX更新出比较方便的版本后再去使用Keil5,因为我在用STM32的时候就是利用Keil5,的确很方便,你们也可以学着用一下。


4.2 主芯片:


  我的主芯片是STM8S系列中的103,其中STM8S的003、005、和103、105,配置一样(外设和CPU频率,FLASH),在代码相同的情况下均可进行烧写。


4.3 代码&解析


  I2C的基本函数代码我已经和传感的代码区隔开来,可以移植,几乎适用于市面上使用I2C驱动的传感器。


4.3.1 SDA、SCL引角初始化


1   //IIC引脚 

2   GPIO_Init(IIC_SCL_GPIO_Port, IIC_SCL_Pin, GPIO_MODE_OUT_PP_HIGH_FAST);

3   GPIO_Init(IIC_SDA_GPIO_Port, IIC_SDA_Pin, GPIO_MODE_OUT_PP_HIGH_FAST);

 

  在引角的控制上面,我选择了直接操作GPIO的寄存器,这样操作比较快,虽然我们感觉不出来,但是省出来的时间越来越多了,也就能够体现出这样写的好处了,不过不理解怎么用的话,也可以使用库函数进行写高、低电平。


  我在SDA引角初始化的时候,选择了推挽输出_高电平_高速,这里就有人会有疑问了,SDA是会进行接收ACK信号的,需要接收即为输入模式,怎么这里改成输出模式,看过我STM8_GPIO介绍的博客的小伙伴应该会想到,怎么不使用开漏输出,这个模式既能接收也能发送。没错,开漏输出模式的确可以,但我在那篇博客中也有说到,开漏输出模式不稳定,通过示波器观察到是斜三角的,而推挽输出是完整的矩形。图我就懒得去弄了 -。-  ,而如何解决推挽输出能够接收ACK的操作看我下一小节。


4.3.1 I2C结构体和引角配置


  这里的结构体是方便I2C多线程,以后需要用到多个I2C接口时候,只需要再定义多一个该结构变量,赋予其他引角便可,省去了再次编写代码的时间和空间。


  我在26和26行编写了两行代码,分别是将SDA模式改成输出和输入模式,直接更改寄存器里的值就能完成实现模式的更换,想知道为什么这样写可以改变模式的话,可以自行百度,也可以察看相对应芯片的寄存器手册。STM8S103中的则在6.2小节中就有介绍。因为讲解起来比较麻烦,这里就不进行更深入的说明了。


 1 /* Struct --------------------------------------------------------------------*/

 2 

 3 typedef struct iic

 4 {

 5   //具体信息:引脚 读写判定

 6   GPIO_TypeDef * pSCL_Port;       //SCL Gpio

 7   uint8_t        uSCL_Pin;        //SCL Pin

 8   GPIO_TypeDef * pSDA_Port;       //SDA Gpio

 9   uint8_t        uSDA_Pin;        //SDA Pin

10   

11   uint8_t        uSDA_Mode_Pin_Position;//SDA Mode

12 

13 }IIC_HandleTypedef;

14 

15 

16 

17 /* Define --------------------------------------------------------------------*/

18 

19 #define IIC_SCL_1(_HANDLE_)  ( (_HANDLE_)->pSCL_Port->ODR |= ( (uint8_t)(_HANDLE_)->uSCL_Pin))

20 #define IIC_SCL_0(_HANDLE_)  ( (_HANDLE_)->pSCL_Port->ODR &= (~(uint8_t)(_HANDLE_)->uSCL_Pin))

21                                   

22 #define IIC_SDA_1(_HANDLE_)  ( (_HANDLE_)->pSDA_Port->ODR |= ( (uint8_t)(_HANDLE_)->uSDA_Pin))

23 #define IIC_SDA_0(_HANDLE_)  ( (_HANDLE_)->pSDA_Port->ODR &= (~(uint8_t)(_HANDLE_)->uSDA_Pin))

24 #define IIC_SDA_R(_HANDLE_)  ( (BitStatus)(_HANDLE_)->pSDA_Port->IDR & (_HANDLE_)->uSDA_Pin)

25 

26 #define IIC_GPIO_SDA_MODE_Opt(_HANDLE_)  (_HANDLE_)->pSDA_Port->ODR |=    (uint8_t)1<<(_HANDLE_)->uSDA_Mode_Pin_Position

27 #define IIC_GPIO_SDA_MODE_Ipt(_HANDLE_)  (_HANDLE_)->pSDA_Port->ODR &=  ~((uint8_t)1<<(_HANDLE_)->uSDA_Mode_Pin_Position)


 4.3.2 延时函数


  延时函数顾名思义,就单纯的延时,延时时间可以根据芯片的速率调整,具体时间通过示波器或者可以观察到脉冲的仪器进行测量即可。


  这里定义了两个延时函数目的是在SCL低电平期间先提前改变SDA的电平,待到SDA电平稳定时,再将SCL电平改变进行读取。


 1 void vIIC_Delay_4us(void)    

 2 {

 3   uint8_t i=3;

 4   while(i--)

 5   {

 6     asm(" NOP");asm(" NOP");asm(" NOP");asm(" NOP");

 7   }

 8     

 9 }

10 

11 void vIIC_Delay_2us(void)    

12 {

13   asm(" NOP");asm(" NOP");asm(" NOP");

14 }

 

4.3.3 IIC引角赋值&结构体参数初始化


  每次调用I2C接口时都需要对IIC的句柄进行初始化。


 1 void vIIC_Handle_Init(IIC_HandleTypedef * hIICx, GPIO_TypeDef * pSCL_Port, uint8_t uSCL_Pin, GPIO_TypeDef * pSDA_Port, uint8_t uSDA_Pin)

 2 {

 3   //GPIO 

 4   hIICx->pSCL_Port = pSCL_Port;

 5   hIICx->uSCL_Pin  = uSCL_Pin ;

 6   hIICx->pSDA_Port = pSDA_Port;

 7   hIICx->uSDA_Pin  = uSDA_Pin ;

 8     

 9     

10   switch(uSDA_Pin)

11   {

12     case GPIO_PIN_0 : hIICx->uSDA_Mode_Pin_Position = 0 ;break;

13     case GPIO_PIN_1 : hIICx->uSDA_Mode_Pin_Position = 2 ;break;

14     case GPIO_PIN_2 : hIICx->uSDA_Mode_Pin_Position = 4 ;break;

15     case GPIO_PIN_3 : hIICx->uSDA_Mode_Pin_Position = 6 ;break;

16     case GPIO_PIN_4 : hIICx->uSDA_Mode_Pin_Position = 8 ;break;

17     case GPIO_PIN_5 : hIICx->uSDA_Mode_Pin_Position = 10;break;

18     case GPIO_PIN_6 : hIICx->uSDA_Mode_Pin_Position = 12;break;

19     case GPIO_PIN_7 : hIICx->uSDA_Mode_Pin_Position = 14;break;

20         

21   }

22 }

 

4.3.4 起始信号


  这里与3.1讲解的操作有点不同,就是3.1中最后没有将SCL拉低包括在内,而为了发送数据的方便,我也将SCL在此函数中拉低了。


 1 void vIIC_Start_Signal(IIC_HandleTypedef * hIICx)

 2 {

 3     

 4   IIC_SDA_1        (hIICx);                        //拉高数据线    

 5   IIC_SCL_1        (hIICx);                        //拉高时钟线

 6   vIIC_Delay_4us   (     );                        //延时

 7   IIC_SDA_0        (hIICx);                        //拉低数据线

 8   vIIC_Delay_4us   (     );                        //延时

 9   IIC_SCL_0        (hIICx);                        //拉低时钟线

10   vIIC_Delay_4us   (     );                        //延时

11     

12 }

4.3.5 结束信号


  这里与3.2讲解的操作也有所不同,因为在数据接收完或者是发送完成后,SDA的电平不能确定,有可能是高也有可能是低电平,但在结束信号的时候,SDA需要是低电平时候拉低SCL才能作为结束信号的开始。


 1 void vIIC_Stop_Signal(IIC_HandleTypedef * hIICx)

 2 {

 3 

 4   IIC_SDA_0        (hIICx);                        //拉低数据线

 5   vIIC_Delay_4us   (     );                        //延时

 6   IIC_SCL_1        (hIICx);                        //拉高时钟线

 7   vIIC_Delay_4us   (     );                        //延时

 8   IIC_SDA_1        (hIICx);                        //拉高数据线

 9   vIIC_Delay_4us   (     );                        //延时

10     

11 }


4.3.6 应答信号(ACK)


  由于因为发送端和操作的不同,这里需要将ACK分成三种,①Ack(主动拉低SDA形成应答信号)  ②NAck(主动不拉低SDA不形成应答信号)  ③ReadAck(等待应答信号)。


  ①Ack(主动拉低SDA形成应答信号)


  该信号在你没有读取到最后一个数据时由主机发送,使从机继续发送数据。


 1 void vIIC_Ack(IIC_HandleTypedef * hIICx)

 2 {

 3 

 4   IIC_SDA_0        (hIICx);                        //拉低数据位

 5   vIIC_Delay_2us   (     );                        //延时    

 6   IIC_SCL_1        (hIICx);                        //拉高时钟位

 7   vIIC_Delay_4us   (     );                        //延时

 8   IIC_SCL_0        (hIICx);                        //拉低时钟位

 9   vIIC_Delay_2us   (     );                        //延时

10     

11 }


②NAck(主动不拉低SDA不形成应答信号) 


  该信号在你读取完最后一个数据时由主机发送,使从机停止发送数据。


 1 void vIIC_NAck(IIC_HandleTypedef * hIICx)

 2 {    

 3     

 4   IIC_SDA_1        (hIICx);                        //SDA拉高 不应答对方

 5   vIIC_Delay_2us        (     );

 6   IIC_SCL_1        (hIICx);

 7   vIIC_Delay_4us        (     );

 8   IIC_SCL_0        (hIICx);

 9   vIIC_Delay_2us        (     );

10     

11 }


③ReadAck(等待应答信号)


  该信号在主机发送完数据后等待从机应答时候使用。


 1 bool bIIC_ReadACK(IIC_HandleTypedef * hIICx) //返回为:=1有ACK,=0无ACK

 2 {                

[1] [2]
关键字:STM8  IIC协议  协议 引用地址:基于STM8的IIC协议--协议篇

上一篇:基于STM8的ADC读取---STM8-第四章
下一篇:解决STM8类型单片机空间太小,使用不了printf串口打印问题

推荐阅读最新更新时间:2024-11-13 11:29

RT-Thread与多家主流芯片厂商签署战略合作协议
国内自主物联网操作系统平台RT-Thread暨上海睿赛德电子科技有限公司宣布:公司已与国内多家主流芯片厂商签署战略合作协议,RT-Thread将作为他们的原生操作系统之一,搭配其芯片推向市场。首批签约公司包括中天微系统、富瀚微电子(300613)、灵动微电子、北京君正(300223)、全志科技(300458)、爱普特微电子、华芯微特科技等企业。此举标志着RT-Thread获得了业界的广泛认同,同时其生态体系建设成效显著。 随着目前国内集成电路产业的快速发展,国内芯片设计企业不断推出MCU、无线SoC等全新的芯片产品。其中许多芯片产品针对相应的物联网应用,需要特别优化或者差异化的操作系统来对其应用软件提供支持,以最好地
[嵌入式]
RT-Thread与多家主流芯片厂商签署战略合作<font color='red'>协议</font>
国轩高科与阿根廷JEMSE公司签署战略合作协议
  近日,国轩高科股份有限公司(简称国轩高科)与阿根廷胡胡伊省国家能源矿业公司(简称JEMSE)以线上签约形式签署战略合作协议。双方决定就当地锂矿资源保障、碳酸锂精炼厂建设、下游业务拓展等方面展开全方位战略合作。   阿根廷胡胡伊省地处南美“锂三角”中心区,盐湖资源集中,开采经验丰富,卤水提锂成本低廉。JEMSE是胡胡伊省省属控股矿业投资公司,致力于持续提升盐湖提锂技术与开采能力,推动光伏储能等新能源利用项目,目前已与法国、澳大利亚、加拿大、美国、日本以及中国的企业建立密切合作。   据协议,国轩高科与JEMSE将合资在胡胡伊省保税区兴建一座电池级碳酸锂精炼厂,后者将提供勘查面积约17000公顷的潜在锂矿产资源探矿及
[新能源]
瑞萨推出精密时钟协议Clock Manager软件,提升时间同步精度
全球半导体解决方案供应商瑞萨电子集团宣布,推出PTP(Precision Timing Protocol,精密时钟协议)Clock Manager软件。作为业界首款基于Linux的时钟管理软件,它为4G、5G和开放式无线接入网(O-RAN)等电信网络(包括前传与回传系统)提供易于使用和访问的同步时钟解决方案。 基于IEEE1588协议的PTP Clock Manager具备API,可通过Linux标准PTP堆栈将瑞萨时钟IC与各种网络处理器相连接,可应对不同应用场景的客户进行PTP同步访问,而无需花费大量时间进行定制。这种与时间戳单元(TSU)无关的方式使客户可以访问他们所选择的处理器/时钟组合,无需自行创建API,从而降低开
[嵌入式]
瑞萨推出精密时钟<font color='red'>协议</font>Clock Manager软件,提升时间同步精度
布局机器人本体业务 现代与哈工智能签署合资经营协议
日前,现代重工与哈工智能签署合资经营协议,由哈工智能或全资子公司与现代重工合作投资设立哈工现代机器人有限公司(暂定名,以下简称哈工现代),哈工智能或全资子公司出资人民币1.4亿元,持70%股权,现代重工拟出资人民币6000万元,持有30%股权。 双方联手,主要是布局机器人本体业务,延伸全产业链。对于哈工智能,将助于其在高端智能装备制造、机器人一站式服务平台、机器人本体三个子板块的智能制造业务布局,以进一步巩固国内市场地位,提高市场占有率。对于现代重工,通过本项目进军中国市场,将给企业带来巨大发展。 据了解,各方将立即启动合资公司设立工作,以及临时产线和智慧工厂建设,预计合资公司2019年可销售机器人1000台,2020年在海宁建
[机器人]
STM8无法跳出TIM2更新中断
刚学STM8,把如何解决调试过程中出现的问题记录下来。 芯片采用的是STM8S103F3P6,准备做一个刷卡模块,其中delay函数是用tim2定时器实现的。在网上下的例程,delay函数的单位是1ms,我觉得间隔时间有点长了,准备改成10us,使用HSE外部晶振8MHz,8分频,计10个数产生更新中断。再做一个ms的延时函数,100个10us延时函数实现。 问题现象: 在运行的过程中,发现timer2初始化,打开中断函数enableinterrupts后,程序无法跳出。 问题分析步骤: 1.我先进行了调试,发现程序在tim2的中断服务函数里无法跳出,一开始我认为可能是清除中断标志位的代码没有执行,或是清除中断
[单片机]
LTE协议栈软件分析测试方法
0引言 LTE(Long Term Evolution)是UMTS技术标准的长期演进,3GPP组织在2004年12月正式立项启动。为达到系统高速率、低时延等要求,对空中接口和系统架构进行了重新设计,来更好地应付如今呈爆炸式增长的数据流量需求。因此空中接口协议栈软件的开发显得极其重要,其软件性能更是直接关系到了网络的服务质量和用户体验。随着LTE网络的商用临近,更多的厂商将加入LTE协议栈软件的研发。 本文介绍了一种应用在LTE协议栈系统软件开发过程的测试和调试的模型,并给出了测试模型的应用结果。该模型以LTE接入网标准架构为原型,分层调试为思想,多彩模块化打印为手段,具有环境简易、调试方便的特点,对协议栈软件调试和分析具有良好的辅
[测试测量]
LTE<font color='red'>协议</font>栈软件分析测试方法
STM8 自带 BootLoader 串口烧录程序
一、进入BootLoader模式 根据STM8的资料可以知道,进入BootLoader的方法只有两种: 空芯片(Flash首地址内容不是0x82或0xAC),上电后即可进入BootLoader模式。 OPTION配置参数地址 487Eh = 0x55 , 787Fh = 0xAA,复位后会进入BootLoader模式。 二、写入OPTION配置参数 通过Flash写入的方式将地址 487Eh 和 787Fh写入0x55和0xAA即可,通过MCU执行一次Flash写入。 1、使用库函数 此方法只适用于可以使用库函数的MCU,记得引用库的头文件 stm8s_flash.h,若MCU不能使用库函数可以使用寄存器方法。 /
[单片机]
<font color='red'>STM8</font> 自带 BootLoader 串口烧录程序
实验6 ADC
ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模数转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。 我们现在学习ADC模块是将介于0V~5V之间的电压值转换成0~1023的数值。STM8S105K4有7个ADC通道,分别对应PB0~PB5、PF4引脚。 如上图所示,该元件是可调电阻,或者叫电位器,103表示10*10^3Ω,即10k欧姆,电位器1脚和2脚之间的阻值为10K,旋转电位器可改变1脚和3脚或者2脚和3脚之间的阻值。1脚接5V,2脚接GND,旋转电位器,可以改变3脚
[单片机]
实验6 ADC
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved