打印

【STM32F0实验】基于STM32 M0的ASK报警接收系统

[复制链接]
9053|43
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 littleshrimp 于 2012-8-31 12:42 编辑

收到在21IC申请的STM32F0开发板已经有一阵子了,因为最近工作比较忙一直没抽出时间来做测试。
前两天21IC的小丫蛋打来电话,要我在指定时间提交实验结果,否则就要收回开发板。
吓的我赶忙把预先想做的实验重新缕一编,编出来这个题目。
然后在后边的贴子会一点点发布测试结果。

笔记+代码
你提供的这个地址有问题呀,打不开。。= =
首先要保证你有设置回复的这个权力。
如果论坛是DZ服务的,在回复可见的内容插入代码

【stm32f0实验】基于STM32 M0的ASK报警接收系统.zip (2.28 MB)
MSP430G2553模块ASK设备
msp430g2553 ASK 模拟.zip (425 Bytes)
沙发
littleshrimp|  楼主 | 2012-8-25 21:27 | 只看该作者
本帖最后由 littleshrimp 于 2012-8-26 22:04 编辑

现在市场上铺天盖地的报警终端多使用315 ASK声表面波射频发射模块,比如红外报警、烟雾报警、煤气报警、门磁报警等。而他们的发射芯片的编码方式基本相同,拆开一个模块会发现里边有一个12位的地址跳线和一个3位的速率路线。

门磁报警模块
每位地址悬空时对应的信号编码为10,跳到1时对应的编码为11,跳到0时对应的编码为00ASK波形如图1所示:
图1

使用特权

评论回复
板凳
littleshrimp|  楼主 | 2012-8-25 21:28 | 只看该作者
本帖最后由 littleshrimp 于 2012-8-26 22:06 编辑

速率跳线只是改变电平的宽度对编码波形不会产生影响,当一次报警触发后主机会多次发送地址码。 ASK接收模块使用MAXIM-IC的MAX7036芯片,MAX7036是一款低成本ASK接收模块,支持300MHz到450MHz频率,频率调节只需要修改晶振大小即可。处理器使用STM32F051R8 CORTEM-M0芯片,STM32F051R8集成32位带有捕获比较功能的定时器和12位DAC可以输出高品质音频。 MAX7036通过DATAOUT引脚输出空中的ASK信号,因为芯片本身不对接收到的信号做滤波处理,所以在没有报警触发时DATAOUT引脚会间歇性输出高出ASK本身的干扰信号。如图2所示:


图2

附上使用EXCEL画的波形图
EXCEL TIMING.zip (26.33 KB)

使用特权

评论回复
地板
littleshrimp|  楼主 | 2012-8-25 21:29 | 只看该作者
通过STM32F051R8 32位定时器的捕获比较功能将每一个电平跳变的时长捕获,通过软件滤波将无用的杂波过滤。
         通过截取有效地址并与系统中绑定的ID相匹配判断哪个模块触发报警,然后通过12DAC输入音频“第XX防区报警”。
系统结构如图3所示:
图3

使用特权

评论回复
5
littleshrimp|  楼主 | 2012-8-25 21:33 | 只看该作者
本帖最后由 littleshrimp 于 2012-8-25 22:09 编辑

程序流程图如图4所示:


图4

接下来就是安装MDK 4.54

安装MDK附带的ST-LINK驱动,驱动文件在MDK的安装路径下的驱动程序。
我的目录是:D:\Keil\ARM\STLink\USBDriver


插上STM32F0-Discovery
系统会提示安装驱动程序,因为我是WIN7,提示无法验证**翅程序软件的发布者,点击始终安装此驱动程序软件完成驱动程序安装。

如果没有其它问题系统会提示安装完成。

在设备管理器的“通用总线控制器”下会看到 STMicroelectronics STLink dongle。说明驱动程序安装正确。

这时开发板的状态为STLink两个红灯长亮,MCU控制的绿灯闪烁。

接下来使用MDK打开从STMCU.ORG下载的示例代码。
我使用的例程是: STM32F0-Discovery_FW_V1.0.0\Project\Peripheral_Examples\TIM_TimeBase


编译后下载并运行。这时
此时开发板的状态为STLink两个红灯长亮,MCU控制的绿灯和蓝灯长亮。





附上STMCU.ORG的例程
stm32f0_stdperiph_lib.zip (11.55 MB)

使用特权

评论回复
6
Harvard| | 2012-8-25 22:35 | 只看该作者
真酷

使用特权

评论回复
7
58180698| | 2012-8-25 22:48 | 只看该作者
哇,还在收回开发版啊?

使用特权

评论回复
8
21小跑堂| | 2012-8-26 01:14 | 只看该作者
这么酷的帖子我要是不督促你,你若忘记发了,那岂不是论坛的一大损失哦!:lol

使用特权

评论回复
9
21小跑堂| | 2012-8-26 01:24 | 只看该作者
哇,还在收回开发版啊?
58180698 发表于 2012-8-25 22:48

哈哈!送出的岂有回收的道理呀!

使用特权

评论回复
10
littleshrimp|  楼主 | 2012-8-26 15:05 | 只看该作者
本帖最后由 littleshrimp 于 2012-8-26 15:09 编辑

基本思路已经清晰,接下来就是写代码。
第一次接触过STM32,首先得测测定时器2的捕获功能。
STM32F0的标准库(stm32f0_stdperiph_lib.zip)里提供了非常丰富的使用例程,实现ASK波形采集的代码可以参考例程:TIM_PWM_Input
路径:STM32F0-Discovery_FW_V1.0.0\Project\Peripheral_Examples\TIM_PWM_Input

首先修改main ()函数中的设置

  //TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;//上升沿捕获
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;//修改为同时捕获上升沿和下降沿

PS:同时捕获两种电平的原因为是,通过图3可以看出一组有效数据的前后有一个很长的低电平。这个低电平可以作为判断几组数据的分隔符,而最后一位数据的电平宽度是由高电平决定的,无法仅通过捕获的低电平来判断。
接下来打开stm32f0xx_it.h文件
定义两个长度为10032位数组用于存放高低电平

__IO uint32_t highlevels[100],lowlevels[100];

定义两个变量用于存放高低电平数组的索引

__IO uint8_t highlevel_index = 0,lowlevel_index = 0;

然后找到用于产生捕获中断的TIM2_IRQHandler()函数
修改代码为

void TIM2_IRQHandler(void)
{
  /* Get the Input Capture value */
  IC2Value = TIM_GetCapture2(TIM2);
         //判断捕获引脚电平
         if(GPIOA->IDR & GPIO_Pin_1)
         {
                   //如果引脚电平为高,说明是上升沿捕获,即前一个电平为低电平.
                   lowlevels[lowlevel_index++] = IC2Value;
         }
         else
         {
                   //否则为高电平
                   highlevels[highlevel_index++] = IC2Value;               
         }
//   if (IC2Value != 0)
//   {
//     highlevels[highlevel_index++] = IC2Value;
//   }
//   else
//   {
//   }      
         if(highlevel_index >100)
         {
                   //ASK数据解码
                   ASK_DECODE();
                   highlevel_index = 0;
                   lowlevel_index = 0;
         }
  /* Clear TIM2 Capture compare interrupt pending bit */
  TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
__nop();
}

编译下载并运行程序,将断点设置在if(highlevel_index >100)内。
使用一个单片机产生占比约83%的方波得到的结果如下图所示:

附上用于测试TIM2捕获的代码:
TIM_PWM_Input.rar (1.11 MB)

使用特权

评论回复
11
dfsa| | 2012-8-26 15:25 | 只看该作者
很不错,鼓励共享

使用特权

评论回复
12
无冕之王| | 2012-8-26 15:40 | 只看该作者
这么酷的帖子我要是不督促你,你若忘记发了,那岂不是论坛的一大损失哦!:lol
21小跑堂 发表于 2012-8-26 01:14

的确是很不错的帖子

使用特权

评论回复
13
yybj| | 2012-8-26 15:45 | 只看该作者
很给力,值得借鉴

使用特权

评论回复
14
秋天落叶| | 2012-8-26 15:56 | 只看该作者
还是得小跑堂在后面催啊,很不错

使用特权

评论回复
15
zhangleiat185| | 2012-8-26 15:59 | 只看该作者
等我小车调好了,也上来秀一秀,呵呵

使用特权

评论回复
16
jialio| | 2012-8-26 21:26 | 只看该作者
提示: 该帖被管理员或版主屏蔽
17
littleshrimp|  楼主 | 2012-8-27 18:24 | 只看该作者
因为前边提到过MAX7036在没有收到信号时它的DATAOUT引脚会间歇输出一个高于实际信号频率的杂波,如果不过滤掉会占用过多的处理器周期。
接下来的工作是做数字滤波,听起来比较好听。其实就是判断电平的宽度,把频率过高的脉冲过滤掉。
定义一个常量用于允许的最小宽度,因为不同的系统中STM32的运行速度不同。这个值取决于STM32的时钟频率和ASK发射模块的速率。min_val要小于STM32捕获到有效数据位的高电平+低电平的最小宽度。

#define min_val 10000

定义一个32位变量用于临时存放高电平。

__IO uint32_t high_t=0;

在捕获中断中将捕获到的高电平存放在临时变量中。
然后在捕获到低电平的判断中判断high_t+ IC2Value(当前低电平的宽度)是否大于最小数据宽度min_val
如果满足条件,则将存放在high_t中的上一个高电平和当前低电平IC2Value添加到数组。否则清除已经捕获的数据,让数组索引从零开始。

                   //如果引脚电平为高,说明是上升沿捕获,即前一个电平为低电平.
                   if(high_t + IC2Value >min_val)
                   {
                            lowlevels[lowlevel_index++] = IC2Value;                  
                            highlevels[highlevel_index++] = high_t;  
                   }
                   else
                   {
                            highlevel_index = 0;
                            lowlevel_index = 0;
                   }

这样就完成了对无效数据的过滤,减小处理器的负荷。

使用特权

评论回复
18
littleshrimp|  楼主 | 2012-8-27 21:43 | 只看该作者
接下来连接MAX7036评估板到STM32F0-Discovery

进入STM32的调试模式,还将断点设置在if(highlevel_index >100)内。
触发报警器发送ID0x00FAAA8AASK信号,这时捕获到的数据如下:

使用特权

评论回复
19
littleshrimp|  楼主 | 2012-8-27 21:46 | 只看该作者
修改ASK_DEC()函数内容为

void ASK_DECODE(void)
{
         uint16_t i,j;
         slave_id=0;
         for(i=1;i<lowlevel_index-25;i++)//循环查找数据间隔
         {
                   if(lowlevels[i-1]/lowlevels[i]>10 && lowlevels[i-1+25]/lowlevels[i+25]>10 )
                   {
                            for(j=i+1;j<i+25;j++)
                            {
                                     slave_id<<=1;
                                     if(highlevels[j]>10000)//数值大于10000视为1,否则为0
                                     {
                                               highlevels[j]=1;                            //无用,仅在分析数据时做为参考
                                               slave_id |=1;
                                     }
                                     else highlevels[j]=0;//无用,仅在分析数据时做为参考
                            }
                            break;
                   }
         }
}

这时解码后的ID如图

与发送ID一至,证明解码成功,此时已经完成ASK的解码。

使用特权

评论回复
20
捡漏王子| | 2012-8-27 21:49 | 只看该作者
不错

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

218

帖子

2

粉丝