找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 21337|回复: 1
打印 上一主题 下一主题
收起左侧

STM8L的I2C基本读写方法详解 含例程

[复制链接]
跳转到指定楼层
楼主
ID:140343 发表于 2016-10-10 00:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM8L的硬件I2C支持100KHz~400KHz的读写速度,作为主设备使用时,不需要配置IO,开启I2C硬件后,对应的IO会自动启用复用功能。本文选取24C02作为I2C从设备,STM8L作为主设备,进行I2C读写功能测试。
STM8L作为I2C主设备时,官方的数据手册给出的配置流程如下图:

详细配置I2C为主设备的流程如下:

①打开I2C外设时钟
②I2C输入时钟频率大小选择
③配置时钟控制寄存器
④配置上升沿时间寄存器
⑤开启I2C功能


STM8L的I2C默认为从设备,当发送一个START信号后,自动从从模式转成主模式.

STM8L的I2C的实现写一字节的描述如下:
①CR2寄存器中的START位被置位后,发送一个起始信号,SR1中的SB被硬件置位.读取SR1寄存器,清除该标志位.
②向DR寄存器写入从设备地址,SR1中的ADDR会被硬件置位,通过读SR1,然后再读SR3,清除该标志位.
③DR寄存器为空后,将从设备寄存器地址写入DR
④DR寄存器为空后,将从要写入的数据写入DR
STM8L读取一字节数据,这里不在赘述.
注意:I2C的时钟频率为2M以下时,根据数据手册,在检测到SB,ADDR,BTF,这些标志位后,必须在其后插入5个NOP再清除标志位.


STM8S中文文档中,对此描述如下.


  1. /*硬件连接*/

  2. // PC0<--->SDA   PC1---->SCL

  3. /****************************************************************************************

  4. *开发环境:IAR for stm8 v6.5.3

  5. *硬件平台:STM8L-DISCOVERY

  6. *功能说明:通过硬件I2C等待的方法,实现对24C02寄存器的读写,借助IAR软件的调试功能,查看变量的数值

  7. *作    者:茗风

  8. ****************************************************************************************/

  9. #include"iostm8l152c6.h"

  10. #include"stdbool.h"

  11. #include"stdint.h"


  12. #define  _5NOPS     asm("nop");asm("nop");asm("nop");asm("nop"); asm("nop")//用于I2C读写延时

  13. /******************************************************************************************************

  14. *  名    称:void delay_10ms(uint8_t x_ms)

  15. *  功    能:延时10ms

  16. *  入口参数:无

  17. *  出口参数:无

  18. *  说    明:

  19. *  范    例:无

  20. ******************************************************************************************************/

  21. void delay_100ms(void)

  22. {

  23.   uint8_t i,j;

  24.   for(i=0;i<255;i++)//2*255个指令周期

  25.     for(j=0;j<255;j++);//2*255个指令周期

  26.   // delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期  

  27.   // 255*2*255+2*255=130610us=130ms

  28.   // 此延时函数,延时时间为130ms

  29.   // 16M/8/2=1M 一个指令周期为1us

  30. }

  31. /******************************************************************************************************

  32. * 名 称: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)

  33. * 功 能:从I2C从设备中读取一字节的数据

  34. * 入口参数:address:读取数据的寄存器地址

  35. * 出口参数:返回一个从I2C从设备指定地址读到的数据

  36. * 说 明:

  37. * 范 例:无

  38. ******************************************************************************************************/

  39. uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)

  40. {

  41.   volatile uint8_t t;

  42.   

  43.   //----------I2C起始信号--------------

  44.   I2C1_CR2_START=1;//产生一个起始条件

  45.   while(!(I2C1_SR1_SB==1));//读SR1寄存器,清除SB标志位

  46.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  47.   

  48.   //-------发送写I2C从器件地址---------

  49.   I2C1_DR=0xA0;//发送从设备地址

  50.   while(!(I2C1_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位

  51.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  52.   if(I2C1_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位

  53.   //  0: Data bytes received

  54.   //  1: Data bytes transmitted

  55.   

  56.   //-----写I2C从器件寄存器地址--------

  57.   I2C1_DR=address;

  58.   while(!(I2C1_SR1_BTF==1));//等待地址发送完成

  59.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  60.   

  61.   //--------I2C重复起始信号-----------

  62.   I2C1_CR2_START=1;//重复产生一个起始条件

  63.   while(!(I2C1_SR1_SB==1));//读SR1寄存器,清除SB标志位

  64.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  65.   

  66.   //-------发送读I2C从器件地址---------

  67.   I2C1_DR=0xA1;//发送从设备地址

  68.   while(!(I2C1_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位

  69.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  70.   if(I2C1_SR3_TRA==1)return 1;//读SR3寄存器,清除ADDR标志位

  71.   while(!(I2C1_SR1_RXNE==1));//等待地址发送完成

  72.   

  73.   //-------------停止信号-------------

  74.   I2C1_CR2_STOP=1;

  75.   

  76.   //-------------读取数据-------------

  77.   t=I2C1_DR;

  78.   

  79.   return t;

  80. }

  81. /******************************************************************************************************

  82. * 名 称:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)

  83. * 功 能:写入一字节的数据到I2C设备中

  84. * 入口参数:address:写入的数据存储地址    dat:待写入的数据

  85. * 出口参数:无

  86. * 说 明: 通过MSTM8L硬件写入I2C设备一个字节的数据

  87. * 范 例:无

  88. ******************************************************************************************************/

  89. uint8_t I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)

  90. {

  91.   volatile uint8_t t;

  92.   //----------I2C起始信号--------------

  93.   I2C1_CR2_START=1;//产生一个起始条件

  94.   while(!(I2C1_SR1_SB==1));

  95.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  96.   I2C1_DR=0xA0;

  97.   

  98.   //--------写I2C从器件地址-----------

  99.   while(!(I2C1_SR1_ADDR==1));

  100.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  101.   if(I2C1_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位

  102.   

  103.   //-----写I2C从器件寄存器地址--------

  104.   while(!(I2C1_SR1_TXE==1));

  105.   I2C1_DR=address;

  106.   

  107.   //-------写I2C数据到寄存器中--------

  108.   while(!(I2C1_SR1_TXE==1));

  109.   I2C1_DR=dat;

  110.   while(!(I2C1_SR1_TXE==1));

  111.   while(!(I2C1_SR1_BTF==1));

  112.   _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时

  113.   

  114.   //-------------停止信号-------------

  115.   I2C1_CR2_STOP=1;

  116.   return 0;

  117. }


  118. /******************************************************************************************************

  119. * 名 称: IIC_init()

  120. * 功 能:初始化IIC

  121. * 入口参数:无

  122. * 出口参数:无

  123. * 说 明:PC0--SDA   PC1--SCL

  124. * 范 例:无

  125. ******************************************************************************************************/

  126. void I2C_Init(void)

  127. {

  128.   //----打开IIC外设时钟----

  129.   CLK_PCKENR1_PCKEN13=1;//

  130.   I2C1_CR1_PE=0;

  131.   

  132.   //----I2C输入时钟频率选择----

  133.   I2C1_FREQR_FREQ=0x02;//2MHz

  134.   /*  The allowed range is between 1 MHz and 16 MHz

  135.   000000: not allowed

  136.   000001: 1 MHz

  137.   000010: 2 MHz

  138.   ...

  139.   010000: 16 MHz                                 */

  140.   

  141.   //----配置时钟控制寄存器----

  142.   I2C1_CCRH_F_S=0; //Standard mode I2C

  143.   I2C1_CCRL=10;    //SCK低电平时间配置

  144.   //I2C的SCK时钟设置为100KHz,则SCK周期为10us

  145.   //因为I2C1_FREQR_FREQ=0x02,即I2C输入时钟频率为2M,周期为0.5us

  146.   //CCR=10时,SCK的低电平时间为tlow=10*0.5us=5us,SCk高电平时间为thigh=10*0.5us=5us

  147.   //所以CCR=10时,SCK输出频率为100KHz

  148.   

  149.   //----配置上升时间寄存器----

  150.   I2C1_TRISER_TRISE=3;//in standard mode, the maximum allowed SCL rise time is 1000 ns.

  151.   //1 us / 0.5 us = 2 + 1


  152.   I2C1_CR1_PE=1;//

  153.   

  154. }


  155. void main(void)

  156. {

  157.   static uint8_t tmp=0;

  158.   I2C_Init();

  159. //  asm("rim");               //enable interrupts

  160.   I2C_WriteOneByteDataToSlave(0x02,0x84);

  161.   delay_100ms();

  162.   tmp=I2C_ReadOneByteDataFromSlave(0x02);

  163.   asm("nop");

  164.   while(1)

  165.   {

  166.     asm("wfi");

  167.   }

  168. }
复制代码




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:161571 发表于 2020-5-15 08:55 | 只看该作者
楼主你好,最近也用到这个8L的单片机,用到了I2C,参考你的代码复制,在调试的时候就一直卡在这while(!(I2C1_SR1_SB==1)); 示波器上是有SCL时钟输出的,请问下楼主有遇到这样的情况吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表