写点什么

STM32L051 测试 (三、I2C 协议设备的添加测试)

作者:矜辰所致
  • 2022-10-12
    江苏
  • 本文字数:3667 字

    阅读完需:约 1 分钟

STM32L051测试 (三、I2C协议设备的添加测试)
前面两篇文章,把L051基本功能都测试过了,确实感觉到ST的CubeMX工具真是好用,对应换芯片的应用来说,着实方便,底层库封装好,上层应用程序基本都一样~~今天我们就来把 I2C 设备添加一下,今天正好借这个机会,把I2C的代码优化一下。
复制代码


本系列博文目录:

STM32L051 测试 (一、使用 CubeMX 生成工程文件 — ST 系列芯片通用)

https://xie.infoq.cn/article/fc5e31ea41e0b33f64b9ee537

STM32L051 测试 (二、开始添加需要的代码)

https://xie.infoq.cn/article/26e83bbc53646042a66e6fb8f

1、CubeMX IO 口的设置

模拟 I2C 的 IO 口都设置为开漏输出,因为电路图上有外部上拉。初始化的时候,2 个 SDA 和 SCL 都得拉高。所以设置如下:


2、HAL 库中的 us 延时函数

在 HAL 库中,只有 ms 的延时函数 HAL_Delay,没有 us 的延时函数,今天用了网上一个延时函数,发现有问题,搞得整个时钟出了问题,郁闷,折腾了一下午。


时间浪费了,通讯模块那边因为这个时钟设置也出了点问题,一直返回复位信息,用了怎么多年的芯片还第一次遇到,Enocean 的 TCM310 模块,主要这个技术支持也不太好找。= =!


还是快速找一个 us 函数,不是那么精确也可以,直接用空语句测试,后面已经经过测试,下面这个函数做的 us 延时可以正常移植以前的 I2C 程序。


/* USER CODE BEGIN 4 */void delay_us(uint32_t Delay){  uint32_t cnt = Delay * 8;    uint32_t i = 0;  for(i = 0; i < cnt; i++)__NOP();}/* USER CODE END 4 */
复制代码

3、移植 I2C 代码

3.1 SHT21 温湿度传感器

代码移植没什么问题,


i2c.c:


#include "i2c.h"
// ------------------------------------------------------------------void i2c_init(void) { // the SDA and SCL pins are defined as input with pull up enabled // pins are initialized as inputs, ext. pull => SDA and SCL = high
}// ------------------------------------------------------------------// send start sequence (S)
void i2c_start(void) { sda_high(); delay_us(10); scl_high(); delay_us(10); sda_low(); delay_us(10); scl_low(); delay_us(10);}// ------------------------------------------------------------------// send stop sequence (P)void i2c_stop(void) { sda_low(); delay_us(10); scl_low(); delay_us(10); scl_high(); delay_us(10); sda_high(); delay_us(10);}// ------------------------------------------------------------------// returns the ACK or NACKuint8 i2c_write(uint8 u8Data) { uint8 u8Bit; uint8 u8AckBit; // write 8 data bits u8Bit = 0x80; //msb first while(u8Bit) { if(u8Data&u8Bit) { sda_high(); delay_us(20); } //& compare every bit else{ sda_low(); delay_us(20); } scl_high(); delay_us(30); u8Bit >>= 1; //next bit scl_low(); delay_us(30); } // read acknowledge (9th bit) sda_high(); delay_us(10); scl_high(); delay_us(10); u8AckBit= sda_read(); //#define sda_read() (sda_port & sda_pin)? 1 :0 ack on bus is low -> u8AckBit = 1 sda_port gpio0 sda_pin SCSEDIO0 delay_us(10); scl_low(); delay_us(10); return u8AckBit;}// ------------------------------------------------------------------// pass the ack/nack // returns the read data uint8 i2c_read(uint8 u8Ack) { uint8 u8Bit; uint8 u8Data; u8Bit = 0x80; // msb first u8Data = 0; while(u8Bit){ scl_high(); delay_us(20); u8Bit >>= 1; //next bit u8Data <<= 1; u8Data |= sda_read(); //(sda_port & sda_pin)? 1 :0 sda_port gpio0 sda_pin SCSEDIO0 delay_us(20); scl_low(); delay_us(50); } // 9th bit acknowledge if(u8Ack==I2C_ACK) { sda_low(); delay_us(20); } //I2C_ACK=0 else { sda_high(); delay_us(20); } scl_high(); delay_us(20); scl_low(); delay_us(20); sda_high(); delay_us(20); return u8Data;}
复制代码


i2c.h:


#ifndef _I2C_H_INCLUDED#define _I2C_H_INCLUDED
#include "main.h"#include "Datadef.h" // #define I2C_CLK_HIGH() HAL_GPIO_WritePin(sht_scl_GPIO_Port,sht_scl_Pin,GPIO_PIN_SET);// #define I2C_CLK_LOW() HAL_GPIO_WritePin(sht_scl_GPIO_Port,sht_scl_Pin,GPIO_PIN_RESET);
// #define I2C_DATA_HIGH() HAL_GPIO_WritePin(sht_sda_GPIO_Port,sht_sda_Pin,GPIO_PIN_SET); // #define I2C_DATA_LOW() HAL_GPIO_WritePin(sht_sda_GPIO_Port,sht_sda_Pin,GPIO_PIN_RESET); // #define I2C_DATA_STATE() (HAL_GPIO_ReadPin(sht_sda_GPIO_Port,sht_sda_Pin) == GPIO_PIN_SET);
// #define sda_high() I2C_DATA_HIGH() // set signals to HIGH first before selecting IN -> slew rates// #define sda_low() I2C_DATA_LOW() // #define sda_read() I2C_DATA_STATE() //ack on bus is low -> u8AckBit = 1
// #define scl_high() I2C_CLK_HIGH() // set signals to HIGH first before selecting IN -> slew rates// #define scl_low() I2C_CLK_LOW()
#define sda_high() HAL_GPIO_WritePin(sht_sda_GPIO_Port,sht_sda_Pin,GPIO_PIN_SET); #define sda_low() HAL_GPIO_WritePin(sht_sda_GPIO_Port,sht_sda_Pin,GPIO_PIN_RESET);#define sda_read() (HAL_GPIO_ReadPin(sht_sda_GPIO_Port,sht_sda_Pin) == GPIO_PIN_SET);
#define scl_high() HAL_GPIO_WritePin(sht_scl_GPIO_Port,sht_scl_Pin,GPIO_PIN_SET);#define scl_low() HAL_GPIO_WritePin(sht_scl_GPIO_Port,sht_scl_Pin,GPIO_PIN_RESET); // ------------------------#define DONOTHING() {;}
// ------------------------// command's#define I2C_WRITE 0 #define I2C_READ 1#define I2C_ACK 0#define I2C_NACK 1
void i2c_init(void);void i2c_start(void);void i2c_stop(void);uint8 i2c_write(uint8 u8Data);uint8 i2c_read(uint8 u8Ack);
#endif
复制代码


SHT21 部分的驱动就不用怎么修改了,基本上直接拿过来,把 ms 延时函数替换一下,就直接用,这里就不贴出来。


测试结果:



板载的 HTU21D,实际测试下来,一直会比空气问题高一点,这个问题,我倒是有点头疼,虽然做过分割,不铺铜等一些处理,还是不尽如人意。

3.1 欧姆龙红外测温 D6T 系列传感器

其实有了上面的成功案例,这个也不是什么问题,还是老样子,定义好 IO 口,写好驱动逻辑。


对于欧姆龙的这个传感器,主要的时序图如下:



其实细节问题在我的另外一篇文章:


FreeRTOS 记录(十、FreeRTOS 实现带 I2C 通讯的 ModbusRTU 协议从机实例)

https://xie.infoq.cn/article/772df429a5a8f3c1db441b298


有过说明,在那篇文章中就是使用的这个传感器。


根据时序图,设计代码,源码如下(当然要根据自己的传感器型号进行细节修改):


void D6T_Measure(){	u8 D6Tbuff[20];	u8 D6T_Data=0;    // u16 tPEC;
i2c_start(); i2c_send_byte(0X14); //地址,和读写指令 i2c_wait_ack(); delay_us(150); //这里必须加
i2c_send_byte(0X4C); i2c_wait_ack();
delay_us(150);
i2c_start(); i2c_send_byte(0X15); //地址,读指令 i2c_wait_ack(); delay_us(120);
// D6T44L_ReadLenByte(5); //D6T-1A-02 只有5个数值 u8 t; D6T_Data=0; for(t=0;t<(5-1);t++) { D6Tbuff[D6T_Data++] = i2c_read_byte(1); delay_us(120); } D6Tbuff[D6T_Data] = i2c_read_byte(0); delay_us(120); i2c_stop();
// tPTAT = 256 * D6Tbuff[1] + D6Tbuff[0]; tP = 256 * D6Tbuff[3] + D6Tbuff[2];}
复制代码


结语


完成了前面的这些基本工作。


下面一篇文章应该会学习 STM32L051 的 flash 读写操作,因为项目中总得有一些设置需要掉线不丢失的,以前 F103 都是直接保存在内部 flash 中,L051 的 flash 读写操作是怎么实现的,下篇文章我们拭目以待!

发布于: 2022-10-12阅读数: 23
用户头像

矜辰所致

关注

CSDN、知乎、微信公众号: 矜辰所致 2022-08-02 加入

不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开! 为了活下去的嵌入式工程师,画画板子,敲敲代码,玩玩RTOS,搞搞Linux ...

评论

发布
暂无评论
STM32L051测试 (三、I2C协议设备的添加测试)_stm32_矜辰所致_InfoQ写作社区