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中文文档中,对此描述如下.

- /*硬件连接*/
- // PC0<--->SDA PC1---->SCL
- /****************************************************************************************
- *开发环境:IAR for stm8 v6.5.3
- *硬件平台:STM8L-DISCOVERY
- *功能说明:通过硬件I2C等待的方法,实现对24C02寄存器的读写,借助IAR软件的调试功能,查看变量的数值
- *作 者:茗风
- ****************************************************************************************/
- #include"iostm8l152c6.h"
- #include"stdbool.h"
- #include"stdint.h"
- #define _5NOPS asm("nop");asm("nop");asm("nop");asm("nop"); asm("nop")//用于I2C读写延时
- /******************************************************************************************************
- * 名 称:void delay_10ms(uint8_t x_ms)
- * 功 能:延时10ms
- * 入口参数:无
- * 出口参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- void delay_100ms(void)
- {
- uint8_t i,j;
- for(i=0;i<255;i++)//2*255个指令周期
- for(j=0;j<255;j++);//2*255个指令周期
- // delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期
- // 255*2*255+2*255=130610us=130ms
- // 此延时函数,延时时间为130ms
- // 16M/8/2=1M 一个指令周期为1us
- }
- /******************************************************************************************************
- * 名 称: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
- * 功 能:从I2C从设备中读取一字节的数据
- * 入口参数:address:读取数据的寄存器地址
- * 出口参数:返回一个从I2C从设备指定地址读到的数据
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
- {
- volatile uint8_t t;
-
- //----------I2C起始信号--------------
- I2C1_CR2_START=1;//产生一个起始条件
- while(!(I2C1_SR1_SB==1));//读SR1寄存器,清除SB标志位
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
-
- //-------发送写I2C从器件地址---------
- I2C1_DR=0xA0;//发送从设备地址
- while(!(I2C1_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
- if(I2C1_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位
- // 0: Data bytes received
- // 1: Data bytes transmitted
-
- //-----写I2C从器件寄存器地址--------
- I2C1_DR=address;
- while(!(I2C1_SR1_BTF==1));//等待地址发送完成
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
-
- //--------I2C重复起始信号-----------
- I2C1_CR2_START=1;//重复产生一个起始条件
- while(!(I2C1_SR1_SB==1));//读SR1寄存器,清除SB标志位
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
-
- //-------发送读I2C从器件地址---------
- I2C1_DR=0xA1;//发送从设备地址
- while(!(I2C1_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
- if(I2C1_SR3_TRA==1)return 1;//读SR3寄存器,清除ADDR标志位
- while(!(I2C1_SR1_RXNE==1));//等待地址发送完成
-
- //-------------停止信号-------------
- I2C1_CR2_STOP=1;
-
- //-------------读取数据-------------
- t=I2C1_DR;
-
- return t;
- }
- /******************************************************************************************************
- * 名 称:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
- * 功 能:写入一字节的数据到I2C设备中
- * 入口参数:address:写入的数据存储地址 dat:待写入的数据
- * 出口参数:无
- * 说 明: 通过MSTM8L硬件写入I2C设备一个字节的数据
- * 范 例:无
- ******************************************************************************************************/
- uint8_t I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
- {
- volatile uint8_t t;
- //----------I2C起始信号--------------
- I2C1_CR2_START=1;//产生一个起始条件
- while(!(I2C1_SR1_SB==1));
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
- I2C1_DR=0xA0;
-
- //--------写I2C从器件地址-----------
- while(!(I2C1_SR1_ADDR==1));
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
- if(I2C1_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位
-
- //-----写I2C从器件寄存器地址--------
- while(!(I2C1_SR1_TXE==1));
- I2C1_DR=address;
-
- //-------写I2C数据到寄存器中--------
- while(!(I2C1_SR1_TXE==1));
- I2C1_DR=dat;
- while(!(I2C1_SR1_TXE==1));
- while(!(I2C1_SR1_BTF==1));
- _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
-
- //-------------停止信号-------------
- I2C1_CR2_STOP=1;
- return 0;
- }
- /******************************************************************************************************
- * 名 称: IIC_init()
- * 功 能:初始化IIC
- * 入口参数:无
- * 出口参数:无
- * 说 明:PC0--SDA PC1--SCL
- * 范 例:无
- ******************************************************************************************************/
- void I2C_Init(void)
- {
- //----打开IIC外设时钟----
- CLK_PCKENR1_PCKEN13=1;//
- I2C1_CR1_PE=0;
-
- //----I2C输入时钟频率选择----
- I2C1_FREQR_FREQ=0x02;//2MHz
- /* The allowed range is between 1 MHz and 16 MHz
- 000000: not allowed
- 000001: 1 MHz
- 000010: 2 MHz
- ...
- 010000: 16 MHz */
-
- //----配置时钟控制寄存器----
- I2C1_CCRH_F_S=0; //Standard mode I2C
- I2C1_CCRL=10; //SCK低电平时间配置
- //I2C的SCK时钟设置为100KHz,则SCK周期为10us
- //因为I2C1_FREQR_FREQ=0x02,即I2C输入时钟频率为2M,周期为0.5us
- //CCR=10时,SCK的低电平时间为tlow=10*0.5us=5us,SCk高电平时间为thigh=10*0.5us=5us
- //所以CCR=10时,SCK输出频率为100KHz
-
- //----配置上升时间寄存器----
- I2C1_TRISER_TRISE=3;//in standard mode, the maximum allowed SCL rise time is 1000 ns.
- //1 us / 0.5 us = 2 + 1
- I2C1_CR1_PE=1;//
-
- }
- void main(void)
- {
- static uint8_t tmp=0;
- I2C_Init();
- // asm("rim"); //enable interrupts
- I2C_WriteOneByteDataToSlave(0x02,0x84);
- delay_100ms();
- tmp=I2C_ReadOneByteDataFromSlave(0x02);
- asm("nop");
- while(1)
- {
- asm("wfi");
- }
- }
复制代码
|