当前位置:首页 > 公众号精选 > 21ic电子网
[导读]有很多传感器手册给了我们时序图,我们只要按照时序图操作就行了,还有一些是标准接口,例如SPI,IIC,UART,这些可以利用硬件提供的收发器通信,还有一些我们没有足够的接口,或者没有对应的接口与之通信,我们可以按照手册提供的时序图,利用IO来完成读写操作。完成的思路是模块化编程思想,将问题逐个分解。由大化小,实现小的功能。

出品  21ic论坛  gaoyang9992006

网站:bbs.21ic.com


有很多传感器手册给了我们时序图,我们只要按照时序图操作就行了,还有一些是标准接口,例如SPI,IIC,UART,这些可以利用硬件提供的收发器通信,还有一些我们没有足够的接口,或者没有对应的接口与之通信,我们可以按照手册提供的时序图,利用IO来完成读写操作。完成的思路是模块化编程思想,将问题逐个分解。由大化小,实现小的功能。

比如常用的单线协议的温湿度传感器DHT21。


可以看到一共40BIT,并注意到是以8BIT为单位的,因此我们可以先规划成每次读取8BIT,读取5次,完成读取。


开始读取时候,假设传感器是空闲的,那么这个时候传感器就是在高电平,主控想要发起读取,要给传感器一个读取的信号,这个信号就是先拉低至少500us,然后拉高20到40us。
因此这个时候,主控的IO要处于输出状态,我们可以输出1,也可以输出0,先输出1,然后输出0,将0持续的事件大于500us,然后输出1
保持20us到40us。

为了靠谱,我这里拉低持续2ms,拉高持续30us,先设置IO的模式为输出模式。
 Write_AM2301_PIN_Init();

拉低这个端口,即输出0
 RESET_AM2301_PIN();


保持2ms,这样就满足最少500us了。
 HAL_Delay(2);

然后拉高它,输出1
 SET_AM2301_PIN();

保持30us
 rt_hw_us_delay(30);

接下来传感器就该响应这个请求了,这个时候就要让主控读取信号的模式了

读取相应,因为接下来器件会主动拉低总线80us,然后再拉高80us.
我们先切换主控的这个IO到输入模式,进行读取。然后判断
器件准备好的这个拉低拉高信号。

第一步,切断刀输入模式,准备读取IO信号
 Read_AM2301_PIN_Init(); Sensor_AnswerFlag=0;

判断是否传感器拉低了总线,拉低表示传感器要发送准备好信号了
 if(Read_AM2301_PIN()==GPIO_PIN_RESET) { Sensor_AnswerFlag=1; Sys_CNT=0;


等待准备好的拉低段80us结束,并计数,看看是否超时。
 while(Read_AM2301_PIN()==GPIO_PIN_RESET) { if(++Sys_CNT>3000) { Sensor_ErrorFlag=1; return 0; } } Sys_CNT=0;

如果准备拉低状态顺利结束,再看看准备信号的拉高状态是否OK
 while(Read_AM2301_PIN()==GPIO_PIN_SET) { if(++Sys_CNT>3000) { Sensor_ErrorFlag=1; return 0; } }

一切OK的话,就该读取实际的传感器输出值了。这个时候要写入到存储传感器40BIT数值的变量里了
每次读取8BIT,一共5此,所以用个循环。方到准备好的变量数组里
 for(i=0;i<5;i++) { AM2301_Data = Read_AM2301_Data();i> }</i>

接下来我们还要实现什么呢,当然是基本的读取8BIT的操作了。



根据这个时序图,可以看出来什么是1,什么是0.
我们看到总线在传输数据时候,拉低都是50us,只有拉高长短不同,长的表示1,短的表示0.
因此我们读取每一位时候,只要先判断是不是低电平或者高电平,就行了。
在低电平时候我们等待,当高电平到来我们判断是否大于28us,因为26us~28us表示0,70us标志1.
所以我们找一个介于28到70us之间的判断阈值。
比如我以30us作为阈值,当低电平结束后,我延时30us,如果是0,这个时候高电平肯定结束了,
如果是1,高电平还在持续。
因此我通过这个思路判断是0还是1.
因为我要读取是8BIT,因此我用循环8次的操作。

unsigned char Read_AM2301_Data(void){ unsigned char i,cnt,buffer,tmp;//要读取8次 for (i = 0; i < 8; i++) { cnt=0;//判断低电平是否结束 while(!Read_AM2301_PIN()) { if(++cnt>=3000) break; }//低电平结束后,进入高电平,开始计时30us rt_hw_us_delay(30); tmp=0;//如果此时还是高电平,那么肯定是大于28us,确定是1来了,赋值1 if(Read_AM2301_PIN()) tmp=1; cnt=0;//等待高电平结束,号进入下一位的读取 while(Read_AM2301_PIN()) { if(++cnt>=2000) break; }//移位写入刚刚得到的1个BIT buffer<<=1; buffer|=tmp; } return buffer;}

接下来实现什么呢?
实现读取IO状态和写高低电平。
unsigned char Read_AM2301_PIN(void){ return HAL_GPIO_ReadPin(AM2301_PORT, AM2301_PIN);}
void SET_AM2301_PIN(void){ HAL_GPIO_WritePin(AM2301_PORT, AM2301_PIN,GPIO_PIN_SET);}
void RESET_AM2301_PIN(void){ HAL_GPIO_WritePin(AM2301_PORT, AM2301_PIN,GPIO_PIN_RESET);}

这里我直接调用的HAL库函数,其实这么做是方便移植,如果你要去其他芯片下使用,你只需要实现这3个函数以及延时函数就行了。逻辑顺序无需修改。最后奉上源码
#include "stm32f0xx_hal.h"
//读传感器 端口位定义,可修改//*#define AM2301_PIN GPIO_PIN_10#define AM2301_PORT GPIOA#define AM2301_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()#define AM2301_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE()

unsigned char Sensor_AnswerFlag; //收到起始标志位unsigned char Sensor_ErrorFlag; //读取传感器错误标志unsigned int Sys_CNT;unsigned char AM2301_Data[5]={0x00,0x00,0x00,0x00,0x00};
void Read_AM2301_PIN_Init(void){ AM2301_GPIO_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = AM2301_PIN; HAL_GPIO_Init(AM2301_PORT, &GPIO_InitStruct);}
void Write_AM2301_PIN_Init(void){ AM2301_GPIO_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = AM2301_PIN; HAL_GPIO_Init(AM2301_PORT, &GPIO_InitStruct);}
unsigned char Read_AM2301_PIN(void){ return HAL_GPIO_ReadPin(AM2301_PORT, AM2301_PIN);}
void SET_AM2301_PIN(void){ HAL_GPIO_WritePin(AM2301_PORT, AM2301_PIN,GPIO_PIN_SET);}
void RESET_AM2301_PIN(void){ HAL_GPIO_WritePin(AM2301_PORT, AM2301_PIN,GPIO_PIN_RESET);}
unsigned char Read_AM2301_Data(void){ unsigned char i,cnt,buffer,tmp; for (i = 0; i < 8; i++) { cnt=0; while(!Read_AM2301_PIN()) { if(++cnt>=3000) break; } rt_hw_us_delay(30); tmp=0; if(Read_AM2301_PIN()) tmp=1; cnt=0; while(Read_AM2301_PIN()) { if(++cnt>=2000) break; } buffer<<=1; buffer|=tmp; } return buffer;}
unsigned char Read_Sensor(void){ unsigned char i; Write_AM2301_PIN_Init(); RESET_AM2301_PIN();// rt_thread_mdelay(2); HAL_Delay(2); SET_AM2301_PIN(); rt_hw_us_delay(30); SET_AM2301_PIN();
Read_AM2301_PIN_Init(); Sensor_AnswerFlag=0; if(Read_AM2301_PIN()==GPIO_PIN_RESET) { Sensor_AnswerFlag=1; Sys_CNT=0; while(Read_AM2301_PIN()==GPIO_PIN_RESET) { if(++Sys_CNT>3000) { Sensor_ErrorFlag=1; return 0; } } Sys_CNT=0; while(Read_AM2301_PIN()==GPIO_PIN_SET) { if(++Sys_CNT>3000) { Sensor_ErrorFlag=1; return 0; } } for(i=0;i<5;i++) { AM2301_Data[i] = Read_AM2301_Data(); } } else { Sensor_AnswerFlag=0; } return 1;}



本文系21ic论坛网友gaoyang9992006原创




免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

21ic电子网

扫描二维码,关注更多精彩内容

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

在数字电路和计算机体系结构中,定序器(Sequencer)是一个至关重要的组件。它负责协调和控制各个功能单元的操作顺序,确保数据在正确的时间被传输和处理。尽管定序器在许多现代电子系统中都扮演着关键角色,但对于非专业人士来...

关键字: 数字电路 计算机 定序器

随着信息技术的飞速发展,数字电路已成为现代电子设备不可或缺的核心组成部分。在数字电路中,数字晶体管作为一种重要的开关元件,发挥着至关重要的作用。本文将详细探讨数字晶体管的基本概念、工作原理、主要类型、应用领域以及未来发展...

关键字: 数字电路 晶体管 开关元件

EDA(电子线路设计座自动化)是以计算机为工作平台、以硬件描述语言(VHDL)为设计语言、以可编程器件(CPLD/FPGA)为实验载体、以ASIC/SOC芯片为目标器件、进行必要元件建模和系统仿真电子产品自动化设计过程。...

关键字: EDA技术 数字电路

EDA 作为现代电子设计的核心, 以大规模可编程逻辑器件(FPGA/COLD)为载体,以计算机为工作平台,在 EDA 软件开发环境下,采用硬件描述语言 HDL(Hardware Description Language)...

关键字: EDA技术 数字电路

移位寄存器是计算机中一种重要的数字电路,它具有广泛的应用。下面我将为您详细介绍移位寄存器的定义、功能和应用。

关键字: 移位寄存器 计算机 数字电路

移位寄存器是一种常用的数字电路元件,广泛应用于计算机、通信、数据处理等领域。它可以实现数据的移位操作,具有较高的灵活性和可扩展性。本文将对移位寄存器的产品性能以及引脚图进行详细分析。

关键字: 移位寄存器 计算机 数字电路

移位寄存器是一种在数字电路中广泛使用的寄存器,它具有许多特点和作用。本文将详细介绍移位寄存器的特点和作用,以及它在各个领域中的应用。

关键字: 移位寄存器 数字电路 计算机

随着工程师们对数字电源这项技术及其优势的熟知,各式各样的数字电源的发展势头日益强劲。电源系统和电源设计人员已经意识到,部署数字电源并不是对现有技术进行革命性转变的全新设计。由于目前市场上数字电源器件种类繁多,设计人员可以...

关键字: 数字电源 数字电路 电源器件

数字电路和接口在越来越高的时钟频率下的表现非常类似于模拟电路。所以,为了确保新设计方案和重新设计的方案中接口的质量,必须引入新的测量方法和测量设备。

关键字: 测试测量 数字电路

电子技术中的模拟电子技术在当前生产生活领域中应用较为广泛,其可理解为处理仿真信号的模拟电路,且与现代许多学科如自动化、电气或数学等保持密切相关。在电子元件选用方面主要以晶体管为主,而实现自动化目标主要得益于其对电路的自动...

关键字: 电子技术 模拟 数字电路
关闭
关闭