标题:
STM8L的I2C基本读写方法详解 含例程
[打印本页]
作者:
51hei小林
时间:
2016-10-10 00:52
标题:
STM8L的I2C基本读写方法详解 含例程
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");
}
}
复制代码
作者:
Blackboy
时间:
2020-5-15 08:55
楼主你好,最近也用到这个8L的单片机,用到了I2C,参考你的代码复制,在调试的时候就一直卡在这while(!(I2C1_SR1_SB==1)); 示波器上是有SCL时钟输出的,请问下楼主有遇到这样的情况吗
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1