历史上的今天
返回首页

历史上的今天

今天是:2025年04月02日(星期三)

正在发生

2019年04月02日 | 总结stm8硬件IIC主模式的寄存器设置及调试心得

2019-04-02 来源:eefocus

一、开发环境


开发软件: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;

}



推荐阅读

史海拾趣

乾坤(Cyntec)公司的发展小趣事

随着国内市场的逐渐饱和,乾坤公司开始将目光投向国际市场。为了打开海外市场,公司积极参加国际电子展会,与海外客户进行面对面的交流与合作。同时,乾坤也加强了与国际知名企业的战略合作,通过技术授权、联合开发等方式,不断拓展其产品的国际影响力。经过几年的努力,乾坤的电子元器件已经成功打入欧美、东南亚等多个国家和地区,公司的国际化进程取得了显著的成果。

EZchip Technologies Ltd公司的发展小趣事

EZchip Technologies Ltd公司自创立之初,就以技术创新为核心驱动力。在21世纪初,网络通信行业飞速发展,对高性能的网络处理芯片需求激增。EZchip团队凭借其深厚的技术积累和对市场敏锐的洞察力,成功研发出了一款具有划时代意义的网络处理器芯片,该芯片以其高效的数据处理能力和低延迟特性迅速获得了市场的认可。随着技术的不断迭代和创新,EZchip逐渐在网络处理器领域建立了技术壁垒,成为了行业的佼佼者。

Abracon公司的发展小趣事

随着技术的不断成熟和市场的认可,EZchip开始寻求更广阔的市场空间。公司通过与全球知名通信设备制造商建立合作关系,将其产品应用于各类网络设备和解决方案中。同时,EZchip还积极参与国际标准制定和行业交流活动,不断提升品牌影响力。通过市场拓展和合作,EZchip的产品逐渐覆盖了全球多个国家和地区,成为了网络通信行业的重要参与者。

EOZ Secme公司的发展小趣事

随着国内市场的饱和,EOZ Secme开始积极寻求海外市场的拓展。公司制定了详细的国际化战略,通过参加国际展会、建立海外销售渠道等方式,逐步打开了国际市场的大门。同时,EOZ Secme还积极与国际知名企业开展合作,共同研发新产品,拓展业务领域。这些努力使得EOZ Secme在国际市场上的影响力不断增强。

Genesis Microchip公司的发展小趣事

随着战后的经济复苏和科技的快速发展,GI开始积极寻求业务多元化和国际化的发展道路。公司不仅继续深耕电子技术领域,还逐渐涉足通信、计算机等多个领域,推出了包括通信设备、计算机硬件在内的多款新产品。同时,GI也积极开拓海外市场,通过设立分支机构、与当地企业合作等方式,成功将产品销往全球多个国家和地区。这一阶段的成功,使GI成为了名副其实的跨国电子巨头。

启攀微电子(Chiphomer)公司的发展小趣事

在技术创新方面,启攀微电子一直致力于提升产品的性能和可靠性。公司拥有一支技术骨干团队,他们拥有丰富的芯片设计开发和批量生产的经验。通过不断的技术创新和优化,公司成功推出了多款高性能、低成本的芯片产品,并在通讯、智能家电及个人消费类等高速成长的电子信息领域取得了广泛的应用。同时,公司还积极拓展海外市场,成功将产品打入韩国等国家和地区,进一步提升了公司的国际影响力。

问答坊 | AI 解惑

继电器的编程,请大家帮忙呀

   请大家指点指点呀,不胜感激        要求是继电器输出低电平时报警, 由于有8个继电器所以必须知道是哪个报警,(下边只写了2个) 报警时都在P2.7口输出 ALARM  CLR  P2.7     ...…

查看全部问答>

TMS320LF2407A矢量控制变频器的开发经验

TMS320LF2407A矢量控制变频器的开发经验…

查看全部问答>

9263中WINCE屏驱动怎么做

买了一个微控VC9263-EK开发板,带了一个3.5寸的竖屏,但我现在要换用别的屏,应该怎样修改屏的驱动的呢?…

查看全部问答>

CE6.0编译出错问题

我是将BSP包中的LCD显示部分文件全部拷到另一个目录下,然后在那个目录下的一个文件里面包含了个头文件(这个头文件在那个LCD显示文件中有定义的),也更改了source文件路径的,然后编译出现一大堆错误。sysgen了也不行的。请问是什么原因? …

查看全部问答>

jrtplib 发送的数据好像收不到?

我使用2440+wince5与PC通过jrtplib通信,现在发现pc可以发送数据到网络,但是wince方面好像不行,抓包发现icmp:port unreachable, 是不是port被占用了呢?而且icmp、udp、tcp刚好是占用同一个字节(指定网络包协议),会不会是字节顺序问题?但 ...…

查看全部问答>

●●高分求教用RDA同步SQL CE 2.0同SQL Server 2000数据的问题●●

用RDA的Pull方法的时候报错: IIS 错误 405 HTTP_STATUS_BAD_METHOD:不允许所使用的HTTP谓词。 --------------------------------------------------------------------- //我的代码 SqlCeRemoteDataAccess rda = new SqlCeRemoteDataAccess(); ...…

查看全部问答>

wince串口不能工作

我的pxa270开发版有4个串口(uart0~uart3),其中uart0用来和超级终端连接打印调试信息,下载了ce5.0。用evc编写的串口程序,打开了COM0:设置好了波特率等后writefile成功,但是不知为什么pc这边无法接收到信息,pc这边发送信息开发版也无法受到。 ...…

查看全部问答>

实现低功耗有哪些常用方法

我在做一个智能电子体温计,要求实现低功耗,系统电流小于0.3毫安。不能用贴片元件,我知道的方法就是所有三极管全用mos管,还有其他方法么?!…

查看全部问答>

用C# 开发mc 1000 应用程序

mc 1000 怎么开启CODE128码,项屏蔽其它码制,如:EAN码等 …

查看全部问答>