tag 标签: stm32f0

相关博文
  • 热度 20
    2012-12-29 21:45
    4427 次阅读|
    0 个评论
    摘要: 本文介绍了无线透传模块之24L01方案的实现,算是我的STM32学习体验吧。文中讨论了24L01的传输特性,并基于此设计了软件实现方式。 一、 背景     基于 24L01 及 STM32F051kxu6 设计了一款无线透明传输模块,作为 STM32F0 的应用实例,详细介绍见: 要求能结合透明无线传输模块的需求,尽量发挥 STM32F0 的优势。 二、 需求分析     基于上述文中所描述的“透明无线传输模块”,首先分析一下它的需求:     a) 能够实现任意字节数据的无线透传;     b) 保证数据传输的准确性和快速性。 三、 概要设计     无线透传模块的工作框图         在进行设计前需要了解 24L01、STM32F0的硬件特性,然后设计控制逻辑。 3.1  24L01工作模式分析     nRF24L01 是一款工作在 2.4 GHz 世界通用 ISM 频段的单片无线收发器芯片。它有六路不同的通道,都可以作为发送和接收的通道。     其引以为优势的ShockBurst模式发送的数据包格式为:         要注意的是:因为数据包中未含帧长信息,所以24L01收、发双方在通讯前要约定好收发数据的长度,否则将无法实现通讯!     那如何实现任意字节数据的发送呢?     如果将六个通道固定发送的字节数依次设置为1、2、4、8、16、32,通过拆包正好可以满足32字节以下任意长度数据的发送。     但最后决定将每次发送的数据固定为32个字节。     主要原因如下:     1、24L01每次发送一包有效的数据,都包含前导码、地址、CRC校验等。所以发送32个字节的数据和发送1个字节的数据时间相差并没有想象的区别大;     2、24L01每次启动发送要延时约130us;     3、24L01如启用自动应答机制,每发送完一个数据包,还要等待应答信号,大约166us。     这些使得固定一次发送 32 字节和分包发送有效数据的时间差距很小,甚至更快。     例如:24L01的发送速率设为最大的2Mbps,当发送31个字节时,采用拆分到不同的通道分5次发送,大概要耗时:(每位数据 0.5us) ((5字节地址 +2字节CRC)*8 *0.5us + 130us+166us)*5次 + 31字节数据*8*0.5us = 1744us     而采用每次固定发送32个字节,大概耗时: (5字节 + 32字节数据 +2字节CRC)*8* 0.5us + 130us +166us=452us     后者更具优势。所以最后决定:无论通过无线发送的数据长度是多少,都固定发送32个字节,兼顾了发送速度和效率。     当发送的数据包中有效数据不足32个字节,接收方如何提取数据呢?     必须在这包数据中设置一字节长度信息,即一次发送最多31字节。     但实际测试时发现:偶尔会收到乱码,推测是 2.4GHz 频段的信号太多所致,所以又添加了一字节长度的反码,以增加有效数据的甄别能力。最后得到数据包的格式如下:   3.2  STM32F0比8位MCU增加的资源     1) 较大的RAM(所用STM32F0为8K),可设置充足的通讯缓冲区,减小了因无线传输不连续导致的串口接收数据被覆盖的可能性;     2) 高速的USART口,最高波特率6 Mbit/s;     3) 丰富的USART中断消息:除经典的收、发有效中断外,新增了字节间隙检测中断(IDLE,连续一字节时间为“1”)、字节空白中断(Break,连续一字节时间为“0”);     4) 可灵活配置的DMA,并提供丰富的中断消息,如传输完成中断(TC)等。 3.3 工作过程设计     因为USART为全双工模式,随时可以收、发数据,所以处理比较简单。          24L01则不同,它是半双工模式,即接收时不能发送,发送时不能接收。     作为无线透明传输模块,待命状态必须是USART和24L01均处于接收状态,以保证随时能收到来自无线或有线的数据。     哪何时将无线收到的数据通过无线转发呢?     按照前面对24L01工作方式的分析,肯定不能每收到一个字节就转发。     因为透传模块无法知道所转发数据的格式,所以也无法等“收完数据包”再转发。     何时触发无线数据发送是无线透明传输模块的主要问题!     我设置了两个触发条件:     1) 串口接收的字节达到一定的长度,按前面的论述,将这一长度设置为30。     2) 接收数据流产生间隙。     如果用8位MCU实现,第一个条件需要通过串口接收计数实现,第二个条件需要用定时器配合实现。     采用STM32F0,则可以方便的使用其特有的资源:     1) 用DMA管理串口数据接收,设定DMA接收字节数为触发长度,通过TC中断实现第一个触发条件;     2) 用USART的IDLE中断监测接收数据流的间隙,实现第二个触发条件。 3.4 详细工作流程设计     接下来就是本工程具体的控制流程设计了。不仅要将串口和24L01两个分别控制好,还要协调好它们之间的关系。     串口方面,要实现将电脑任何时刻发送过来的任意长度的数据以数据包的格式保存在缓冲区。     无线方面,要在满足触发条件后将数据转发出去,并能够将收到的数据保存在缓冲区内。     通过串口的RXNE中断可知道串口开始接收数据。     何时串口完成一串数据转存到缓冲区呢?     举例说明,当UASRT连续接收了32个字节,程序处理如下:     初始化时打开RXNE的中断使能,关闭IDLE和TC的中断标志。     当收到第一个字节触发RXNE后,关闭RXNE的中断使能,打开IDLE和TC的中断使能。启用DMA处理USART数据接收,通过RX的DMA通道将数据转移到缓冲区中。     收到第30个字节触发DMA的TC中断,与此同时完成如下几件事:     A) 将数据长度和长度的反码保存在数据包的前两位;     B) 关闭所有接收完成中断使能,打开开始接收中断使能;     C) 将缓冲区的数据块标号加1.     紧接着第 31个字节触发 RXNE,在进行类似上述操作后,当接收到第 32 个字节后触发 IDLE 中断,完成同于 TC 中断时的事。     触发 IDLE 中断后如何确定收到有效数据的长度呢?DMA 有函数可以读取已收到的数据长度。     以上描述的是 USART 收到数据通过无线转发的过程。那无线收到数据后如何通过 USART 转发呢?     因为 USART 的发送处理很简单,无线收到一包数据后,填入 USART的发送缓冲区,并根据包长设置好发送的字节数,启动 USART 发送即可。          借助STM32F0 的DMA功能更为简单。 四、 总结     通过这个项目的尝试,初步体验了32位MCU和8位MCU的差别,同时感受了通过STM32库函数编程的方便之处。     通过启用STM32F0的DMA等资源,可大大简化程序,使流程更加清晰。     但也体验到由于其较为丰富的中断触发方式,在使用中断资源时需仔细理解各种中断状态的含义,否则将导致不断进入中断。 发现的问题:     24L01的自动应答机制并不能完全消除误码,甚至带来一些麻烦,如实际接收方已经收到数据,也发回了应答,但发送方未收到应答信号,此时该如何处理?还望有高手指点!
  • 热度 18
    2012-8-6 18:13
    6371 次阅读|
    3 个评论
    第一课  STM32F0 学习笔记 一、硬件          STM32F0 discovery          MB1034B (二)库文件夹的规划 借鉴已有 STM32 系列产品的库规划, STM32F0 的库规划一开始就做得比较好(个人观点)。 解压库文件后,放在任意一个文件夹下,均可以编译例子文件。下图中 Libraries 文件夹是库文件,仅有 2.22M ,以后我们自行开发的时候,只要将这个文件夹复制到自己的工程文件所在文件夹中,就可以避开烦人的绝对路径问题。          Utilities 文件夹中保存的是有关于这块硬件电路板( STM32F0 discovery )引脚定义之类的文件。 Project 文件夹中是所有的例子文件 ,Demonstration 中包含了为各种不同编译工具建立的例子工程,我们自己做开发时,只要将 Demostration 文件夹复制到自己的工程文件夹中,然后将其改名即可。稍后我们会讨论这一问题。 Project 文件夹中的内容 Master_Workspace 是用了新版 Keil 提供的工作区功能,即 Muilt-Project WorkSpace ,建立一个工作区,将所有例子全部集中在一个 WorkSpace 中,这样便于学习,如下图所示。 而 Peripheral_Examples 文件夹中则是包括了所有的例子文件。 将所有例子文件放在一个 WorkSpace 中 (三)资料 见下图。          6 份 PDF 文件分别是:( 01_STM32F051x ) STM32F0 系列的中文数据手册( 39 页),( 02_STM32F051x )参考手册( 715 页),( DM000499929 )用户手册(英文, 46 页),( DM00049931 )应用笔记( 18 页),( DM00050135 )用户手册( 35 页),工具( 3 页)。 2 个压缩包分别是 ST-LINK 的驱动程序和 STM32F0 的库文件。 (四)使用 Keil 学习例子时的一个常用功能 打开设置对话框,选中 Browse Information ,编译通过后看源程序,如果遇到看不懂的定义,将光标移入,果断按 F12 就可以了,,,, 这是 main.c 中一个没看懂的符号,将光标移入,然后按下 F12 (前提是已编译通过哦) 看到了吧,在 stm32f0xx_gpio.h 中有个定义。          还是看不懂,,,,那请补一补 C 语言知识吧。 这个时代很多人学东西已不再遵循“循序渐进”的原则,而是“项目式”,出现这样的现象是很正常的。这好不好我不敢说,反正这应该是一种常态了,很多人会出现这样的情况。而有规划的“项目式”教学也正是我的研究领域,,,话多了,打住。  
  • 热度 26
    2012-8-6 11:05
    4236 次阅读|
    7 个评论
    变量 TimingDelay 被赋值了 Delay 函数传递进来的那个 nTime 值,也就是 50 或 100 。如果变量 TimingDelay 不等于 0 ,那么它就将一直循环,无法退出 Delay 函数,只有当 TimingDelay 变为 0 了,才能够退出 Delay 函数。我们正怀疑那个 TimingDelay 变量怎么会变成 0 的呢?看:就在这里了。 有个名为 TimingDelay_Decrement ()的函数在做这个工作,可以这个函数又被什么调用的呢?就是 SysTick_Handler 函数了。看到这儿,我们已隐隐猜到,这个 SysTick_Handler 函数应该是个中断函数,每隔一段时间定时运行一次。因为我们找不到有其他函数调用这个函数,所以它只能是被硬件机制调用的。那每隔多长时间呢?这个不难猜,应该是 1ms 一次。 总结一下: SysTick_Handler ()函数每 ms 运行一次,运行时就调用 TimingDelay_Decrement ()函数,而这个函数令变量 TimingDelay 减 1 。 这样,当我们给 Delay ()函数传递一个 50 的参数( Delay(50) )时,相当于延时 50ms 。 可是,可是,问题还有很多,为什么 SysTick_Handler 会 1ms 运行一次呢? 看来,得研究一下 SysTick 究竟是个什么东西,它是怎么运作的了。 三、 SysTick          SysTick 被称之为系统嘀嗒定时器。查找 STM32F0 的数据手册,居然就这么一点点介绍,,,好在,我们还有其他资料。 在 Cortex-M3 权威指南中是这么描述 Syteick 的:          难怪,这个 Systick 是 Cortex-M3 内核所提供的, ST 自然没必要多讲了。          SysTick 定时器:系统滴答定时器是一个非常基本的倒计时定时器,用于在每隔一定的时间产生一个中断,即使是系统在睡眠模式下也能工作。它使得 OS 在各 CM3 器件之间的移植中不必修改系统定时器的代码,移植工作一下子容易多了。          下面还有另外一个问题, Systick 究竟多长时间产生一次中断。          看 main.c 中的代码: if (SysTick_Config(SystemCoreClock / 1000))   {     /* Capture error */     while (1);   } 我们可以猜测,那个 1000 就是关键。让我们把 1000 改成 100 ,重新编译再运行,结果是灯闪烁的速度慢了 10 倍,也就是 Systick 变成了 10ms 中断一次。这样,我们就学会了怎么样来改变这个 Systick 。可是,总觉得这还有点不够,为什么会是这样呢?让我们把鼠标移到 SystemCoreClock 上去按下 F12 吧。          这次跑到了 system_stm32f0xx.c 文件中去了,这就是 User 组中的第 3 个文件。查看一下,原来符号: SystemCoreClock 是一个变量,它的值是 48000000 ,也就是 48M ,这好像是个挺熟悉的数值,是什么呢? 打开 STM32F051 芯片介绍的资料,原来在这儿, 48M 是该芯片运行的最高频率。 那么我们可以猜测: ( 1 )在这个例子中,我们把芯片运行到了它的最高频率,即 48M ( 2 ) 48M 除 1000 就是 48 000 ,应该是将这个 48000 这个数放到了某个寄存器中,然后根据这个数来分频。也就是时钟脉冲的频率是 48M ,然后每隔 48000 出来一个 Systick ,这样,这个 Systick 就是 1ms/ 次了。 讲到这里,似乎把 Systick 理解了,但其实还有更多的疑问,为什么这个芯片是运行在 48M ?既然是最高,那肯定还有其他的值,如何设置?好奇是人进步的阶梯,不过要是一直纠缠下去,这一篇就没法结束了。我们先强压住自己的好奇心,暂时到此为止吧。
  • 热度 18
    2012-8-6 11:04
    5568 次阅读|
    2 个评论
    第二课  让灯闪起来 systick 应用实例 一、               工程的构成   可以看到, ST 官方例子中,一个 Systick   Project 下分成四组,分别是 User , STM32F0-Discovery , STM32F0XX_StdPeriph_Driver 和 MDK-ARM ,在每个组别下面都有一些文件。 其中 User 文件组下面的文件都是针对这个 Project 而编写的,也是根据需要可以随时改写的。当然,这些文件的写法也有一些模板可供参考。   STM32F0-Discovery 文件夹下是关于这块板硬件的一些定义,如 LED 接在哪个引脚上,按钮接在哪个引脚上等等。 STM32F0XX_StdPeriph_Driver 文件夹则是库文件, STM32F0 的功能很多,针对不同的功能,库用了不同的文件来描述。如 stm32f0xx_gpio.c 用来描述有关 GPIO 引脚的特性,这样的文件一共有 10 多个,显然,在一个具体的例子中并非所有功能都会用到,因此,在这组文件中只需要挑选用到的文件就行了。 MDK-ARM 是用来描述 ARM 核的文件。注意这些文件上都是有一把小钥匙的,显示这些文件是被锁住了,不能更改。   二、               例子的研究 把 main.c 文件打开,去掉那些注释,我们可以看到,它也就是那么几行: GPIO_InitTypeDef GPIO_InitStructure; static __IO uint32_t TimingDelay; void Delay(__IO uint32_t nTime); int main(void) {     /* Initialize Leds mounted on STM32F0-discovery */   STM_EVAL_LEDInit(LED3);   STM_EVAL_LEDInit(LED4);     /* Turn on LED3 and LED4 */   STM_EVAL_LEDOn(LED3);   STM_EVAL_LEDOn(LED4);     if (SysTick_Config(SystemCoreClock / 1000))   {     while (1);   }     while (1)   {     STM_EVAL_LEDToggle(LED4);// 反转 LED4 的状态(亮 / 灭互换)       Delay(50);          // 延时 50ms       STM_EVAL_LEDToggle(LED3);// 反转 LED3 的状态(亮 / 灭互换)       Delay(100);   // 延时 100ms   } }   void Delay(__IO uint32_t nTime)     // 延时函数 {   TimingDelay = nTime;   while(TimingDelay != 0); }   void TimingDelay_Decrement(void)         // 用来将 TimingDelay 变量减 1 的函数 {   if (TimingDelay != 0x00)   {     TimingDelay--;   } } 看了这几行程序,我们要解开的疑惑实在是太多了, LED3 , LED4 两个符号哪里来的,为什么它们就表示了板上的两个 LED ?为什么 50 就是 50ms ?这是怎么实现的?除开 main.c 文件外,其他文件有什么用处?如果一一解释,那一篇文章的篇幅就太大了,我们先抓主体,然后抠细节吧。 打开 stm32f0xx_it.c 文件,去掉一堆我们暂时还不清楚什么用途的代码后,我们找到了这样的一行: 原来它在这里执行了 TimingDelay_Decrement ()函数。而正是这个函数让变量 TimingDelay 减 1 的。而在 Delay ( … )函数中, void Delay(__IO uint32_t nTime)     // 延时函数 {   TimingDelay = nTime;   while(TimingDelay != 0); }
相关资源