总结stm8硬件IIC主模式的寄存器设置及调试心得

2019-04-02来源: eefocus关键字:stm8  硬件IIC  主模式  寄存器设置

一、开发环境


开发软件:STVD


芯片型号:stm8s103


硬件接口:I2C(主模式)


二、寄存器主要用到的功能(按用户手册的顺序)


1. I2C_CR1(控制寄存器1):


(1)bit0:控制I2C模块的启动/禁用。此功能主要用于I2C总线初始化的时候,配置TRISER相关寄存器功能的时候必须先禁用I2C模块才可以进行写操作。


2. I2C_CR2(控制寄存器2)


(1)bit7:设置1实现软复位I2C模块。当I2C总线始终处于繁忙状态的时候通过复位实现恢复。


(2)bit3:设置ACK应答的位置。在I2C总线初始化的时候配置,通常是作清零操作,用于表示ACK位控制被移位寄存器正在接收的这个当前字节的应答或者不应答。


(3)bit2:设置ACK应答使能。这个位需要根据协议决定是否需要使能ACK,并在I2C主机每读取来自从机的一字节数据之前进行设置,这样硬件II2C就会自动在读取到数据后作出对应的ACK响应。实际上这个ACK应答是始终存在的,如果该位为0,表示当前应答位为NACK,许多I2C设备在读取最后一个字节的数据的时候会要求主机回复的是NACK,其实就是把该位设置为0即可。


(4)bit1:设置该位用于产生停止位。用于释放总线,也就是总线恢复闲置状态。


(5)bit0:设置该位用于产生起始位。产生起始位后,进入主模式。


3. I2C_FREQR(频率寄存器)


(1)bit5~0:设置外设时钟的频率。有效的取值范围0b000001~0b110010表示1MHz~50MHz。在I2C总线初始化的时候配置;如果用内部晶振,数值设置为16即可表示外设时钟的频率是16MHz;如果用的是外部晶振,根据外部晶振的时钟频率设置对应的数值即可。


4. I2C_OARL(自身地址寄存器LSB)


(1)bit7~1:设置主机在I2C总线上自身的地址(地址的第7:1位)。


(2)bit0:设置主机在I2C总线上的自身地址(地址的第0位,在地址位数为10的时候有效)




5. I2C_OARH(自身地址寄存器MSB)


(1)bit2~1:设置主机在I2C总线上的自身地址(地址的第9:8位,在地址位数为10的时候有效)




6. I2C_DR(数据寄存器)


(1)bit7~0:用于存放接收到的数据或放置用于发送到总线的数据。这个寄存器的用法很简单,主机需要往从机写数据的时候把数据按字节写入此寄存器即可,主机需要往从机读数据的时候把这个寄存器内的数据读取并写入变量中即可。




7. I2C_SR1(状态寄存器1)


(1)bit7:通过判断该位可以知道写入I2C_DR的数据是否已经全部发送出去,从而决定是否开始发送下一个字节的数据。


(2)bit6:通过判断该位可以知道是否接受到来自从机的数据,该位被置位的状态下,从I2C_DR中读取数据才是有意义的。


(3)bit1:通过判断该位可以知道需要与主机进行通讯的从机地址是否已经发送。


(4)bit0:通过判断该位可以知道起始位是否已经发送。




8. I2C_SR2(状态寄存器2):目前开发过程中没有用到该寄存器。




9. I2C_SR3(状态寄存器3):目前开发过程中没有用到该寄存器。




10. I2C_ITR(中断寄存器):如果开发时希望特定事件以中断形式通知,可以通过该寄存器来实现。比如,写入一字节数据至I2C_DR寄存器后,CPU处理其它事件,当收到TXE触发的中断事件后,再写下一字节数据。这样CPU在处理整个I2C读写事件的过程中可以不需要进行循环判断等待。




11. I2C_CCRL(时钟控制寄存器低位部分),I2C_CCRH(时钟控制寄存器高位部分)


(1)这两个寄存器在I2C总线初始化的时候进行配置,需要注意的是这两个寄存器需要在I2C模块禁用的状态下改变值。


(2)I2C_CCRH的bit7:如果I2C通讯速度小于等于标准速度(100KHz),该位置0;如果I2C通讯速度大于标准速度,则该位置1表示是快速模式(比较常用的是400kHz)


(3)I2C_CCRL的bit6:表示快速模式下的占空比,即I2C总线的SCL时钟信号的低电平时间(t_low)与高电平时间(t_high)的比值。t_low+t_high就是一个SCL时钟信号脉冲周期的长度,i2c总线的通讯速度f_scl = 1/(t_low+t_high)。假如单片机采用16MHz的外部晶振且I2C通讯速度是400KHz的情况下,


(4)I2C_CCRH的bit3:0以及I2C_CCRL的bit7~0共12个bit表示CCR的值。CCR的具体计算方式举个例子大致描述一下:假如单片机采用16MHz的外部晶振(即t_ck=16)且I2C通讯速度是400KHz的情况下,此时采用占空比为16:9(I2C_CCRL的bit6设置为1),则CCR=(t_ck)/[1/(t_low+t_high)*(25)]=(16*1000000)/(400000*25)= 1




12. I2C_TRISE(TRISE寄存器)


(1)bit5~0:在快速/标准模式下的大上升时间(主模式)。这个时间需要根据从机的特性需求来设置。


标准模式(100KHz)下的计算公式:(1000ns / t_pclk1 + 1) ns; t_pclk1为从机的最大上升时间


快速模式(400KHz)下的计算公式:(300ns / t_pclk1 + 1)ns




三、调试心得


1. 如果外设时钟的频率小于10MHz,建议在标准模式(100KHz通讯速度)下进行开发调试。


2. 发送从机地址时(7-bit),需要加上1bit读写位(0为写,1为读),拼成一整个字节进行发送。


3. 发送完地址+读写字节后,必须对I2C_SR3寄存器进行读操作,实现清状态寄存器,否则总线会堵死。


4. 读取数据前需设置ACK应答,如果需要NACK则设置ACK应答位为0(示例函数中ACK设置为0,需根据协议需求进行修改)




四、读写函数代码


1. 主机往从机读一个字节数据:


#define I2C_OVER_TIME   0xFA  // 超时处理时间需要根据晶振频率调整

#define SLAVE_ADDR_WR   0x20  // 7-bit从机地址 + 1-bit写信号

#define SLAVE_ADDR_RD   0x21  // 7-bit从机地址 + 1-bit读信号

u8 I2C_Read_Byte(u8 reg, u8 *pdata)

{

u16 cnt = 0;


    /* Generate start & wait event detection */

    I2C->CR2 |= 0x01; 

while (!(I2C->SR1 & 0x01))

{

if ( ++cnt > I2C_OVER_TIME )

{

/* Generate stop signal */

    I2C->CR2 |= 0x02; 

return 1;

}

}


cnt = 0;

/* Send slave Address in write direction & wait detection event */

    I2C->DR = SLAVE_ADDR_WR;

while (!(I2C->SR1 & 0x02))

{

if ( ++cnt > I2C_OVER_TIME )

{

/* Generate stop signal */

    I2C->CR2 |= 0x02;  

return 1;

}

}

    I2C->SR3;


cnt = 0;

/* Send register to be read */

I2C->DR = reg; 

    while(!(I2C->SR1 & 0x80))

{

if ( ++cnt > I2C_OVER_TIME )

{

/* Generate stop signal */

    I2C->CR2 |= 0x02; 

return 1;

}

}

    

    cnt = 0;

/* Generate start & wait event detection */

    I2C->CR2 |= 0x01; 

while (!(I2C->SR1 & 0x01))

{

if ( ++cnt > I2C_OVER_TIME )

{

/* Generate stop signal */

    I2C->CR2 |= 0x02; 

return 1;

}

}


cnt = 0;

/* Send register to be read */

I2C->DR = SLAVE_ADDR_RD; 

    while(!(I2C->SR1 & 0x02))

{

if ( ++cnt > I2C_OVER_TIME )

{

/* Generate stop signal */

    I2C->CR2 |= 0x02;  

return 1;

}

}

I2C->SR3;


cnt = 0;

I2C->CR2 &= ~0x04; //nack 

/* waiting for byte from slave */

while (!(I2C->SR1 & 0x40))

{

if ( ++cnt > I2C_OVER_TIME )

{

/* Generate stop signal */

    I2C->CR2 |= 0x02; 

return 1;

}

}

    *pdata = (u8)(I2C_ReceiveData());


    /* Generate stop signal */

    I2C->CR2 |= 0x02; 


return 0;

}


2. 主机往从机写一字节数据:

u8 I2C_Write_Byte(u8 reg,u8 data)  

u16 cnt = 0;


/* Generate start & wait event detection */

I2C->CR2 |= 0x01;

while (!(I2C->SR1 & 0x01))

{

if ( ++cnt > I2C_OVER_TIME )

{

I2C_GenerateSTOP(ENABLE); 

return 1;

}

}


cnt = 0;

/* Send slave Address in WRITE direction & wait detection event */

I2C->DR = SLAVE_ADDR_WR;

while (!(I2C->SR1 & 0x02))

{

if ( ++cnt > I2C_OVER_TIME )

{

I2C_GenerateSTOP(ENABLE);

return 1;

}

}

I2C->SR3;


cnt = 0;

/* Send internal register address to write */

I2C->DR = reg;

while(!(I2C->SR1 & 0x80))

{

if ( ++cnt > I2C_OVER_TIME )

{

I2C_GenerateSTOP(ENABLE);

return 1;

}

}


cnt = 0;

/* Send Data to write */

I2C->DR = data;

while (!(I2C->SR1 & 0x80))

{

if ( ++cnt > I2C_OVER_TIME )

{

I2C_GenerateSTOP(ENABLE);

return 1;

}

}

 

    I2C_GenerateSTOP(ENABLE); 


return 0;

}



关键字:stm8  硬件IIC  主模式  寄存器设置 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/2019/ic-news040243680.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:stm8 IAR 编译错误Fatal Error[Cp001]
下一篇:STM8L051的硬件I2C调试

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM8S配置位 OptionByte
 1.什么是STM8S 的配置字 OptionByte2.Option Byt Byte 里面的位都表示什么3.如何编程Option Byte一 选项字节(OptionByte )STM8S 的配置字类似于AVR 的Fuse 熔丝位。用于配置端口的复用功能和读保护等操作。不同于AVR 的熔丝位,STM8S 的时钟配置并不在Option Byte 中,不会出现写完STM8S 后芯片直接锁死的尴尬。选项字节用于配置硬件特性和存储器保护状态,这些字节位于同一页的特定存储器阵列中。选项字节可以在ICP/SWIM模式中或IAP模式中修改, 也就是可以通过STlink 写配置字,或者是通过程序写选项字。举例:STM8S 的有一个
发表于 2020-04-27
STM8S配置位 OptionByte
STM8 IAR新建寄存器工程
.2.3.4.添加头文件目录转化为相对目录5.设置输出文件目录6.设置仿真工具
发表于 2020-04-27
STM8 IAR新建寄存器工程
stm8l151低功耗程序架构,调试心得
最近帮医院做了一款体温记录仪,整个硬件方案资源是:stm8L151 + NTC*2 + EEPROM + 锂电池充电保护电路 + 18mAh纽扣电池;软件逻辑是,每隔一分钟,采样两路温度并保存在EEP里;通过USB转TTL,上位机能够读取,展示温度曲线,最大最小平均值等简单的运算;整个方案很简单,但也走了不少弯路......单片机程序框架之伪代码:void main(void){    CLK_Config();    GPIO_Config();    ADC_Config();    USART_Config();   
发表于 2020-04-27
STM8设计几点需要注意的地方
1>、STM8的PC0、PC1两个引脚输出只有OD开漏输出,没有PP输出,如下图所示:如果想要使用PC0和PC1输出高电平,硬件设计的时候需要进行上拉,这两个端口无法进行软件上拉,只能靠硬件上拉。2>、使用STM8库函数的时候,函数GPIO_ReadInputDataBit()无法读取引脚的高电平,需要对库函数做修改
发表于 2020-04-25
STM8设计几点需要注意的地方
STM8SF103----ADC采集电压值
){ u16 u16_adc1_value; Init_ADC();//初始化ADC1 while(1) { ADC1_StartConversion();//ADC开始转换      u16_adc1_value = ADC1_GetConversionValue();//保存转换值 }}
发表于 2020-04-25
STM8使用STVD开发环境问题
1、编译时出现.ubsct size overflow--http://blog.sina.com.cn/s/blog_817a5eb601018186.html----------- Project roewe - STM8 Cosmic - Configuration Debug -------------Running Linkerclnk -l"C:Program FilesCOSMICCXSTM8Lib"  -o Debugroewe.sm8 -mDebugroewe.map Debugroewe.lkf#error clnk Debugroewe.lkf:1 segment .ubsct
发表于 2020-04-25
小广播
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved