完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM8单片机价格低廉,而且支持硬件仿真,在一些小型项目中,使用这样的单片机可以降低成本。而且STM8单片机外围电路简单,只需要在VCAPVCAP引脚接一个电容,晶振什么玩意都不需要。 但是不是所有人都能用好这个芯片的,特别是这个芯片的IIC。很多人都说这个地方有问题。故,在这里详细的说明一下STM8的IIC。 为了便于摘录芯片手册内容说理,本文选择一款STM8的具体芯片来描述。 众所周知,单片机与外设进行IIC通信一般有两种方式,一种是IO口模拟出IIC协议,另一种是使用硬件IIC。由于IIC的时序逻辑其实并不复杂,所以很多人喜欢使用IO口模拟IIC,这样操作方便。故我们先介绍IO口模拟出IIC。 如果没使用过STM8的人,一定会觉得,模拟IIC特别简单,对于不同的单片机来说,时序都是一样的,移植不就是操作IO口吗?这有什么好说的呢。那么请各位想一想会怎样操作呢? 答:IIC的SCK线不需要读数据,直接定义为输出。SDA呢,就定义两个宏,一个让SDA脚输出,一个让SDA脚输入,写数据时,让SDA输出,读数据时,让SDA输入。为了能够使用模拟IIC和硬件IIC,所以我们使用硬件IIC那两个脚方便软件编写。 上面这段话,可谓是非常标准的答案了,毫无瑕疵。如果有朋友给我这样的答案,我就面带微笑看着他,让他试。除非运气特别棒,否则,一般是没法成功的。我们来看看这是为什么。 首先,你得在电路上给两个引脚加了上拉电阻。 STM8的引脚是具有推挽输出和上拉输入的,所以很多人为了省事,会直接用引脚连接外部设备,如24C02之类的EEPROM等。 我们看看STM8S003F3P6引脚图,如图: STM8这两个引脚标注了T,表示是纯开漏引脚。纯开漏引脚输0时为低,输出1为高阻态,而非高电平。所以,这两个脚不加上拉是无法正常进行通信的。 即时你运气好,加了上拉电阻,也还只是迈出了第一步。 很多人为了切换引脚输入输出会使用类似下面的宏定义: //IO方向设置 #define IIC_SDA_IN() {GPIOB->DDR&=0XDF;} #define IIC_SDA_OUT() {GPIOB->DDR|=0X20;} STM8S003F3P6的SDA是PB5,Px_DDR寄存器相应位置1为输出,清0为输入。这样操作是没什么问题的。 但是我们看看STM8对IO控制的两个寄存器,Px_CR1和Px_CR2。 CR1对真正开漏输出没有影响,我们不用考虑。 但是CR2这一位影响就大了。如果之前设置输出为1,输出速度为10M。那么在切换为输入模式时,就会将SDA脚的中断使能。而且坑爹的是,STM8S003F3P6中断时按组来弄的,就是所有PB脚进一个中断。而且只要这里开了中断,并且开了全局中断,就算是打开了中断,不用其它操作。 那么现在就酸爽了,每当你要读数据时,引脚就开启中断模式,然后数据位就纷纷触发中断,如果你没有使用PB脚中断,那么只会进入stm8s_it.c中一个空的中断函数,如果你用了,那么恭喜你,整个程序乱七八糟了。 那么究竟正确的方式如何呢?我们来看两个地方: 第一是芯片手册引脚描述: 对于PB5脚,就是一个低速脚,所以,初始化的时候,给一个高速根本没有意义。 第二,是IDR寄存器。 根据这里的描述,发现没?我们只需将SDA脚设置为输出模式就OK,根本不用在读数据时,将引脚切换为输入模式。 所以最后总结一下,STM8使用模拟IIC时,只需将引脚设置为低速输出模式即可。 库函数操作如下: //初始化IIC void IIC_Init(void) { //由于STM8单片机,可以在输入和输出条件下读取IO口状态,故直接设置为输出。 GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_SLOW ); GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_SLOW ); IIC_SCL_H; IIC_SDA_H; } 寄存器操作 //初始化IIC void IIC_Init(void) { //由于STM8单片机,可以在输入和输出条件下读取IO口状态,故直接设置为输出。 GPIOB->DDR|=0X30;//PB4,PB5设置为输出 GPIOB->CR2&=0XCF;//PB4,PB5设为低速。PB4可也可设置为高速 IIC_SCL_H; IIC_SDA_H; } 下附程序 myiic.h文件 #ifndef __MYIIC_H #define __MYIIC_H #include "sys.h" //SCL-PB4 #define IIC_SCL_H (GPIOB->ODR |= (1 << 4)) #define IIC_SCL_L (GPIOB->ODR &= ~(1 << 4)) //SDA-PB5 #define IIC_SDA_H (GPIOB->ODR |= (1 << 5)) #define IIC_SDA_L (GPIOB->ODR &= ~(1 << 5)) #define IIC_SDA_R ((GPIOB->IDR & (1 << 5))>>5) //IIC所有操作函数 void IIC_Init(void); //初始化IIC的IO口 void IIC_Start(void); //发送IIC开始信号 void IIC_Stop(void); //发送IIC停止信号 void IIC_Send_Byte(u8 txd); //IIC发送一个字节 u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节 u8 IIC_Wait_Ack(void); //IIC等待ACK信号 void IIC_Ack(void); //IIC发送ACK信号 void IIC_NAck(void); //IIC不发送ACK信号 void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data); u8 IIC_Read_One_Byte(u8 daddr,u8 addr); #endif myiic.c文件 #include "myiic.h" void delay_us() { nop(); nop(); nop(); nop(); } //初始化IIC void IIC_Init(void) { //由于STM8单片机,可以在输入和输出条件下读取IO口状态,故直接设置为输出。 GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_SLOW ); GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_SLOW ); IIC_SCL_H; IIC_SDA_H; } //产生IIC起始信号 void IIC_Start(void) { IIC_SDA_H; IIC_SCL_H; delay_us(); IIC_SDA_L; //START:when CLK is high,DATA change form high to low delay_us(); IIC_SCL_L; //钳住I2C总线,准备发送或接收数据 } //产生IIC停止信号 void IIC_Stop(void) { IIC_SCL_L; IIC_SDA_L;//STOP:when CLK is high DATA change form low to high delay_us(); IIC_SCL_H; IIC_SDA_H;//发送I2C总线结束信号 delay_us(); } //等待应答信号到来 //返回值:1,接收应答失败 // 0,接收应答成功 u8 IIC_Wait_Ack(void) { u8 ucErrtime=0; IIC_SDA_H;nop(); IIC_SCL_H;nop(); while(IIC_SDA_R) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL_L;//时钟输出0 return 0; } //产生ACK应答 void IIC_Ack(void) { IIC_SCL_L; IIC_SDA_L; delay_us(); IIC_SCL_H; delay_us(); IIC_SCL_L; } //不产生ACK应答 void IIC_NAck(void) { IIC_SCL_L; IIC_SDA_H; delay_us(); IIC_SCL_H; delay_us(); IIC_SCL_L; } //IIC发送一个字节 //返回从机有无应答 //1,有应答 //0,无应答 void IIC_Send_Byte(u8 txd) { u8 t; IIC_SCL_L;//拉低时钟开始数据传输 for(t=0;t<8;t++) { if((txd&0x80)>>7) IIC_SDA_H; else IIC_SDA_L; txd<<=1; delay_us(); //对TEA5767这三个延时都是必须的 IIC_SCL_H; delay_us(); IIC_SCL_L; delay_us(); } } //读1个字节,ack=1时,发送ACK,ack=0,发送nACK u8 IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; for(i=0;i<8;i++ ) { IIC_SCL_L; delay_us(); IIC_SCL_H; receive<<=1; if(IIC_SDA_R)receive++; nop(); } if (!ack) IIC_NAck();//发送nACK else IIC_Ack(); //发送ACK return receive; } |
|
相关推荐
|
|
调了一整天的iic终于调通了,楼主的程序可以用,我的模拟iic程序在stm32上可以用,stm8死活不行,现在终于好了,非常感谢,强调一点stm8s模拟iic不用改变SDA引脚的输入输出方向。
|
|
|
|
|
|
感谢分享!不过我在调试时出现 读取16位数据 高8位正确 低8位不存在的情况(全0),检查发现 在写入函数中(写入16位数据),低8位的数据根本没写进去,这是什么原因呢? 现在用的是 stm8s003f3p6, 之前用STM32f103开发板调试,数据都是正常的。
下面是我读写函数: void LDC1612_WriteDATA(u8 addr,u16 dt) { IIC_Start(); delay_us(); IIC_Send_Byte(0x54); //发送总线地址 IIC_Wait_Ack(); IIC_Send_Byte(addr); //发送从机寄存器地址 IIC_Wait_Ack(); IIC_Send_Byte(dt>>8); IIC_Wait_Ack(); IIC_Send_Byte(dt); IIC_Wait_Ack(); IIC_Stop(); delay_us(); } u16 LDC1612_ReadDATA(u8 addr) { u16 temp=0; IIC_Start(); IIC_Send_Byte(0x54); IIC_Wait_Ack(); IIC_Send_Byte(addr); //发送从机地址 IIC_Wait_Ack(); delay_us(); IIC_Start(); IIC_Send_Byte(0x55); IIC_Wait_Ack(); temp=IIC_Read_Byte(1); // 0 代表 NACK IIC_Ack(); temp=(temp<<8)|IIC_Read_Byte(0); IIC_NAck(); IIC_Stop(); return temp; } |
|
|
|
|
|
fdh1 发表于 2016-12-27 16:49 接受函数中已经包含ACK了,你仔细看看 |
|
|
|
|
|
stm8L的把这个改下
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK u8 MPU_IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; IIC_SDA_H; for(i=0;i<8;i++ ) { IIC_SCL_H; receive<<=1; if(IIC_SDA_R)receive++; IIC_SCL_L; MPU_IIC_Delay(); // MPU_IIC_Delay(); } if (!ack) MPU_IIC_NAck();//发送nACK else MPU_IIC_Ack(); //发送ACK return receive; } |
|
|
|
优优秀优秀优秀优秀秀优秀优秀优秀优秀优秀优秀优秀优秀优秀优秀优秀优优秀优秀优秀优秀秀优秀优秀优秀优秀优秀优秀优秀优秀优秀优秀优秀
|
|
|
|
|
|
非常赞赏!有理有据,实验成功,实测应该在IIC_Stop函数里SCL置高之后加一个延时,以使停止信号稳定,STM8s105芯片上实测,不加延时,逻辑分析仪分辨不出是停止信号,按理说执行顺序造就了肯定是SCL高要提前与SDA高,可能主频高了(16MHz)以后,数据不稳定,观察发现两个上升沿无明显的先后顺序,加延时后可以分辨出是停止信号,(注意slave设备的速度,延时函数要在时序要求的时间内抬高或拉低电平)供其他网友参考!
|
|
|
|
|
|
本帖最后由 saya0769 于 2019-11-5 13:52 编辑
谢谢博主。十分感谢啊。调了几天。参考了N个博客。最后在这里调好了。谢谢楼主。虽然之前是由于杜邦线断开了。 |
|
|
|
|
|
1168 浏览 0 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
1105 浏览 2 评论
2203 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1297 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1718 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 01:10 , Processed in 1.023190 second(s), Total 84, Slave 73 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号