专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
51单片机
信号处理 --- 方波信号的检测方法之查询法
2020-03-08 19:23
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
51单片机
7417
2
2
本帖最后由 会笑的星星 于 2019-12-30 23:11 编辑
我们之前讲了采用计数法来检测方波,虽然这种方法比较简单,也能试用一定的场合,但是无法解决精确识别方波的问题。有时候,我们需要比较精确的检测方波的每一个周期,因为每一个周期代表的是不同的信息,比如一种常用的无线编码格式 --- 1527编码,周期为16T(T的长度一般在几百微秒以上)的方波在占空比为4:16表示0,占空比为12:16时表示1,如下图所示。
事实上,在实际应用中有不少无线通信协议采用的就是类似1527的编码方式。这种方式编码简单,容易检测,同样能满足一些应用需求。下面我们就来解决如何检测类似1527编码的方波问题,这种方法也被为称之为查询法,它只需要一个硬件定时器外加一个IO口读取信号电平就可以完成检测,电路接口如下图所示。
在检测信号之前,我们先制定一下协议。把0表示为高电平:低电平为1T:3T。把1表示为高电平:低电平为3T:1T,其中1T我定为300us,如下图所示。
有了0、1的表示方法,我们就知道将一个或者多个字节的数据表示成方波的方法,接收者按照这个方法就能知道发送者发了什么数据。由于发送者需要与接收者处于同步状态,以便接收者知道发送者要开始发送数据了,因此还需要在发送数据之前增加一个被称为同步头的方波(事实上,UART、IIC等协议都有类似的同步头)。同步头方波必须与表示0、1的方波明显的区分开来,我把高电平:低电平定为1T:9T,如下图所示。
有了同步头,数据,还需要一个结束码,这是为了让最后一位数据对应的方波信号能被正确的识别出来(IIC、UART等协议都有类似的结束机制)。结束码采用高电平:低电平=1T:1T,如下图所示。
最后,做一个约定,数据传输时高位在前,低位在后,对于接收者而言先接收到位的放在字节高位。这样同步头、数据位、结束码组成的完整数据帧就有了,如下是发送数据的例子。
有了协议上的准备,我们就可以检测方波信号了。
先描述一下我们要解决的问题。
检测一个由上述编码方式编码的4个字节数据,其中前3个字节为信息字节,第四个字节为前3个字节的校验和
。电路接口如下图所示。
我们先分析一下这个问题。我们知道1T的时间是300us,一位(也就是一个方波周期)的时间总长度就是4*300=1.2ms。由于1T的时间较长,所以我们可以考虑在一个定时间隔小于1T的硬件定时器中读取信号脚的电平状态,从而确认方波周期表示0还是表示 1。这里要注意一下,过小的定时间隔会导致程序总被无故中断,显然也是不可取的,因此需要选取一个合适的定时间隔是必要的,这里取100us(小于1T的1/3),这样确保能比较精确的查询方波信号的同时也不会过多的中断程序的运行。这样我们只需要使用一个硬件定时器资源加一个外部IO口就能解决这个问题。如下图所示。
有了上述的分析,我们就可以编写程序了。
//字节数量
#define FRAME_BYTE_LENGTH 3
//字节数量对应的位数量
#define FRAME_BIT_LENGTH (FRAME_BYTE_LENGTH*8)
//信号脚
#define SIGNAL_GPIO GPIO
struct
{
unsigned char done_flag;
unsigned char fifo[FRAME_BYTE_LENGTH];
}rev_data;
void app_data_detect(void )
{
static INT8U prev_read = 0,read_period = 0,
read_low_cnt = 0,read_high_cnt = 0,read_bit_cnt = 0;
static INT8U read_buff[FRAME_BYTE_LENGTH];
unsigned char i;
if (SIGNAL_GPIO == 1)
{
if (prev_read == 0)
{
//read_period表示代表一个数据位的方波持续多少个100us。在这里一个方波的
//长度是4*300 = 1200us,read_period = 1200 / 100 = 12
//考虑误差因素,取read_period ± 4做为有效方波
if ((read_period >= 8) && (read_period <= 16))
{
//如果对方波高电平计时大于对低电平的计时,这个方波表示的数据位为1,并把
//数据为保存到缓存中
if (read_high_cnt > read_low_cnt)
{
read_buff[read_bit_cnt / 8] |= (0x01 << (0x07 - (read_bit_cnt % 8)));
}
read_bit_cnt++;
if (read_bit_cnt >= FRAME_BIT_LENGTH)
{
//数据接收完成
rev_data.done_flag = 1;
read_bit_cnt = 0;
for (i = 0; i < FRAME_BYTE_LENGTH; i++)
{
rev_data.fifo[i] = read_buff[i]
read_buff[i] = 0x00;
}
}
}
else
{
read_bit_cnt = 0;
for (i = 0; i < FRAME_BYTE_LENGTH; i++)
{
read_buff[i] = 0x00;
}
}
read_high_cnt = 0;
read_low_cnt = 0;
read_period = 0;
}
read_high_cnt++;
read_period++;
prev_read = 1;
}
else
{
read_period++;
read_low_cnt++;
prev_read = 0;
}
}
//硬件定时器,定时间隔为100us。
void timer_interrupt()
{
app_data_detect()
}
main()
{
while(1)
{
if(rev_data.done_flag)
{
unsigned char sum;
sum = rev_data[0] + rev_data[1] + rev_data[2];
if(sum == rev_data[3])
{
//如果校验成功,处理数据
}
rev_data.done_flag = 0;
}
}
}
复制代码
使用查询方法检测方波信号我们就说完了,虽然这种方法在能比较准确的识别方波信号,但是如果方波信号的周期很短(比如小于10us),我们就不能使用这个方法。因此,这种方法也有一定的局限性。对于如何检测频率更高的方波,我们下一篇文章在讨论。希望本文所讲的方波检测方法能对你有启发。
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
1条回答
会笑的星星
1楼-- · 2020-03-08 23:00
加载中...
一周热门
更多
>
相关问题
【东软载波ESF0654 PDS开发板活动】开箱
1 个回答
东软载波ESF0654 PDS开发板外部中断
1 个回答
东软载波ESF0654 PDS开发板高级控制定时器AD16C4T
1 个回答
用串口调试助手为什么只能在hex模式接收发送而在文本模式不行
9 个回答
触摸芯片SC02B/SC04B在地砖灯的设计方案
1 个回答
东软载波ESF0654 PDS开发板串口USART0代码分享
1 个回答
普通32位单片机使用linux的应用代码
5 个回答
东软载波ESF0654 PDS开发板AT24C04的调试
9 个回答
相关文章
51单片机与蓝牙模块连接
0个评论
51单片机的硬件结构
0个评论
基于51单片机的无线遥控器制作
0个评论
51单片机 AD转换
0个评论
51单片机数码管递增显示
0个评论
如何实现对单片机寄存器的访问
0个评论
基于51单片机的指纹密码锁
0个评论
×
关闭
采纳回答
向帮助了您的网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
51单片机
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
关闭
您已邀请
15
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
一周热门 更多>