历史上的今天
返回首页

历史上的今天

今天是:2024年11月25日(星期一)

正在发生

2019年11月25日 | STM8L051F3 硬件I2C从机实例

2019-11-25 来源:eefocus

这篇文章是以相对新手的水平去写给新手参考的,所以我会尽量写的详细点。


1.首先我们需要查看数据手册,看下硬件I2C的接口是哪个端口,我用的是STM8L051F3这一块芯片。

通过手册可以知道,这款芯片的I2C端口为C0跟C1(一开始忘记去查手册,傻呼呼的用别的端口调试了很久。。。)

这款芯片的I2C应该是不能复用别的端口的,反正手册我没查到,只能用C0跟C1。


2.接下来开始初始化I2C需要的设置。(这里我只讲7位地址的。)


void I2C_Init(void)


{


  CLK_PeripheralClockConfig(CLK_Peripheral_I2C1, ENABLE); //初始化I2C时钟

  CLK->SWR=CLK_ICKCR_HSION;//时钟选择为HSI

  CLK->CKDIVR = 0;   //时钟不分频

  CLK->PCKENR1 = 0x08; // 使能I2C时钟

  


/* Init GPIO for I2C use */ //初始化端口C0和C1

GPIOC->CR1 |= 0x03;

GPIOC->DDR &= ~0x03;

GPIOC->CR2 &= ~0x03;


//初始化I2C寄存器

I2C1->CR1 |= 0x01;         // Enable I2C peripheral

I2C1->CR2 = 0x04;       // Enable I2C acknowledgement

I2C1->FREQR = 16;       // Set I2C Freq value (16MHz)

//下面这里要重点说明一下,STM8L051F3的硬件I2C作为从机是可以具备2个地址的。(用不到的话等下不要使能地址2即可)

I2C1->OARL = (0x44<< 1) ; // 地址1 = 0x44.第0位是10位地址的0位,7位地址要左移1位。

I2C1->OARH = 0x40;       // 此位需要置1,看手册。

I2C1->OAR2 = (0x46 << 1)|0x01; //这里是地址2 = 0x46的寄存器,第0位置1是使能2个地址,如果用不到直接屏蔽此语句即可。

I2C1->ITR = 0x07;      // all I2C interrupt enable  使能I2C中断

}


3.记得开启中断(enableInterrupts();),下面看中断内容。


中断里面我们需要2组数组来储存收发的数据,这个自己在主函数里定义2个全局变量数组,大小为你自己想需要收发的数据看有多少了。


#define MAX_Id 10

u8 Slave_Buffer_Tx[MAX_Id];

u8 Slave_Buffer_Rx[MAX_Id];


下面是一个广播地址的


INTERRUPT_HANDLER(I2C_IRQHandler,29)

{

unsigned char Add;

unsigned char Nuse;

static unsigned char RX_Cnt=0;


if(I2C1->SR2&0X0F) //I2C 出现错误

{

I2C1->SR2&=0xf0;

//I2C->CR2|=1<<7;

//I2C->CR2&=~(1<<7);

RX_Cnt=0;

I2C_Tx_Idx=0;

I2C1->SR2 |=0x02;

}


if(I2C1->SR1&0X02) //地址匹配

{

(void)(I2C1->SR3); //先读I2C_SR1,再读I2C_SR3,就可以清除ADDR

// I2C->DR = 0X00;

I2C_Tx_Idx=0;

I2C_Rx_Idx=0;

I2C1->DR = Slave_Buffer_Tx[I2C_Tx_Idx++];

}

if(I2C1->SR1&0X10) //停止条件

{

Nuse = I2C1->CR2; //清除停止位(SR1第4位),先读SR1,再写CR2

nop();

I2C1->CR2 = Nuse;

}

if(I2C1->SR1&0X04) //BTF位,先读SR1,再读或者写DR寄存器清除

{

Nuse=I2C1->DR;

// I2C->DR=Nuse;

}

if(I2C1->SR1 & 0x40) //RXNE,数据寄存器是否为空,0空1非

{

//将收到的数据储存到RX数组中。虽然我们是从机,用不到这里的数据,但是这里必须读DR寄存器收取数据.不然会出错

Slave_Buffer_Rx[I2C_Rx_Idx++]=I2C1->DR;

if(I2C_Rx_Idx>=MAX_Id)

{

I2C_Rx_Idx=0;

}

}

if(I2C1->SR1 & 0x80) //将发送的数据放入DR寄存器,清除TXE

{

I2C1->DR = Slave_Buffer_Tx[I2C_Tx_Idx++];

if(I2C_Tx_Idx>=MAX_Id)I2C_Tx_Idx=0;

}


}


下面是2个广播地址的


//这款芯片的中断文件在这里文件里面(stm8l15x_it.c),I2C的中断向量就是这个。

INTERRUPT_HANDLER(I2C_IRQHandler,29)

{

unsigned char Add;

unsigned char Nuse;

static unsigned char RX_Cnt=0;

B_I2C *base;


if(I2C1->SR2&0X0F) //I2C 出现错误中断的处理。没特别的中断需要处理的话,这里直接复制就好。

{

I2C1->SR2&=0xf0;

RX_Cnt=0;

I2C_Tx_Idx=0;

I2C1->SR2 |=0x02;

}


//第七位判断是从机地址1还是地址2,选择等下接收到的数据要放在哪个结构体里面(或者你们自己替换成变量也可以的,只是把收到的数据存起来而已,之后我们才可以去调用)

if(I2C1->SR3&0x80)

{

base = &B_I2C_p1;//add1

}

else

{

base = &B_I2C_p2_0x46;//add2

}


if(I2C1->SR1&0X02) //SR1的第一位会检测广播地址是否匹配

{

(void)(I2C1->SR3); //先读I2C_SR1,再读I2C_SR3,就可以清除ADDR

// I2C->DR = 0X00;

I2C_Tx_Idx=0;

I2C_Rx_Idx=0;

I2C1->DR = Slave_Buffer_Tx[I2C_Tx_Idx++];

}

if(I2C1->SR1&0X10) //停止条件

{

Nuse = I2C1->CR2; //清除停止位(SR1第4位),先读SR1,再写CR2

nop();

I2C1->CR2 = Nuse;

}

if(I2C1->SR1&0X04) //BTF位,先读SR1,再读或者写DR寄存器清除

{

Nuse=I2C1->DR;

// I2C->DR=Nuse;

}

if(I2C1->SR1 & 0x40) //RXNE,数据寄存器是否为空,0空1非

{

//将收到的数据储存到RX数组中。虽然我们是从机,用不到这里的数据,但是这里必须读DR寄存器收取数据.不然会出错

Slave_Buffer_Rx[I2C_Rx_Idx++]=I2C1->DR;

if(I2C_Rx_Idx>=MAX_Id)

{

I2C_Rx_Idx=0;

}

}

if(I2C1->SR1 & 0x80) //将发送的数据放入DR寄存器,清除TXE

{

I2C1->DR = Slave_Buffer_Tx[I2C_Tx_Idx++];

if(I2C_Tx_Idx>=MAX_Id)I2C_Tx_Idx=0;

}


}


很多人都说硬件I2C不稳定,不好用,不过就我目前测试来讲,还是挺稳定好用的.

推荐阅读

史海拾趣

Adaptive Interconnect Electronics, Inc. [AIE]公司的发展小趣事

AIE公司始终将品质管理作为企业发展的核心。公司建立了严格的质量管理体系,从原材料采购到产品生产、销售等各个环节都进行严格的监控和管理。同时,AIE还注重与客户的沟通和反馈,及时了解客户的需求和意见,不断改进产品和服务。这种对品质的执着追求和对客户的尊重赢得了客户的广泛信任和支持。

Aptiv公司的发展小趣事

作为一家具有社会责任感的企业,Aptiv始终关注社会公益事业。公司积极参与各项社会活动和慈善捐赠,为改善社会环境和提升公众生活质量做出了积极贡献。同时,Aptiv还注重在运营所在城市推动社区发展,通过创造就业岗位、支持教育事业等方式,为当地社会经济的繁荣做出了贡献。

南晶电子(DGNJDZ)公司的发展小趣事

在发展过程中,南晶电子始终秉持合作共赢的理念。公司与上下游企业建立了紧密的合作关系,共同推动产业链的发展。同时,南晶电子还积极参与社会公益事业,为社会进步和发展贡献自己的力量。通过与各方的共同努力,南晶电子在电子行业树立了良好的企业形象和口碑。

Frequency Devices公司的发展小趣事

为了进一步扩大市场份额,Frequency Devices公司积极实施国际化战略。公司通过参加国际电子展会、建立海外销售网络、与国际知名企业建立合作关系等方式,不断提升品牌国际影响力。同时,公司还根据不同国家和地区的市场特点,定制化开发符合当地需求的高频电子产品。这些努力使得Frequency Devices公司的产品成功打入多个国际市场,实现了全球化布局。

台湾凌通(Generalplus)公司的发展小趣事
电源电压不稳定可能导致指示灯闪烁。可检查电源电压是否稳定,或尝试更换更稳定的电源。
Entegris公司的发展小趣事

在晶圆盒传输业务上,Entegris与台湾的家登精密之间发生了一场长达数年的专利侵权诉讼。Entegris最终获得了胜诉,家登被要求赔偿超过3,000万美元。这一胜利不仅保护了Entegris的知识产权,也进一步巩固了其在半导体材料市场的地位。

问答坊 | AI 解惑

嵌入式汽车数字仪表设计

1 引言     汽车仪表是驾驶员与汽车的信息交流界面,对汽车安全以及经济行驶具有重要作用。近年来,随着汽车电子技术的发展,汽车仪表显示信息也不断增加,而传统机械指针式汽车组合仪表则无法满足现在使用需求。特别是计算机、微电子和 ...…

查看全部问答>

extern ROMChain_t *OEMRomChain; 这段编译错误

在eboot main.c 添加 multibin xip 过程中, 添加 InitRomChain() 函数中,引用了 全局变量 extern ROMChain_t *OEMRomChain; OEMRomChain 指针对应是 public\\common\\oak\\inc\\Bcoemglobal.h 文件中 #define OEMRomChain g_pOemGlobal->pRO ...…

查看全部问答>

开机

我的电脑密码记不得,如何解开电脑的密码,在哪里进行操作,登陆密码,各种操作系统的解发,请大家帮助 急急................................…

查看全部问答>

个人求有PHS基站控制器软件开发经验辅导老师(可兼职,深圳)

本人欲从事PHS基站控制器软件开发,因无此方面的经验,想请位有这方面经验的辅导老师。 主要工作是帮助本人分析一个现有PHS基站控制器软件源程序,然后修正程序中的一些BUG。 时间方面可以是灵活按排(工作日、业余均可),报酬可以按时/日/周/月等 ...…

查看全部问答>

Linuxlogo显示

请问linuxlogo默认是在左上角显示的,现在要求显示到右下角,并且企鹅图像倒置 相当于把默认显示转180度,请问这个哪里可以改。 可以修改fbcon.c吗?新人求救!!…

查看全部问答>

(++急)有偿请求解决单片机串口多机通信程序问题

各位大侠们,麻烦帮忙看看这个例子,是我毕业设计的题目,由于单片机C编程学得不精,这几天一直在调程序都没法调出来,还请各位大虾们帮帮忙!万分感激!!! 硬件实现功能: 1、从机U2按键按下,在本机显示,同时将按键值送往主机U1,在主机显示 ...…

查看全部问答>

中*美*爱*梯*科*技, 9月10日新班开课, 免费试听!

中*美*爱*梯*科*技, .NET外企软件工程师班将于2007年9月10日开课, 开课第一周免费试听, 欢迎大家踊跃报名参加!   中*美*爱*梯*科*技向学员郑重承诺: 百分之百保证就业, 月薪3000——8000, 就不了业者退还全部学费!    ...…

查看全部问答>

有熟悉STM32编程的进来帮个忙

1,#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || ;请问这个加了红色背景的是什么意思;特别是IS—是什么意思,后面这一句是什么意思…

查看全部问答>

642图像缩放问题

各位高手:642采集的图像好像是720*480的大小吧,如果用jpeg编码,出来的图像也是720*480,现在我想请问的是我采集720*480大小的图像,用jpeg编码,并缩小成320*240(注:不是在原图上截取,而是大小缩放),请问该如何做,或者采集的时候就重新取样 ...…

查看全部问答>