2024年4月18日发(作者:)
课程设计说明书
题 目:
课 程:
院 (部):
专 业:
班 级:
学生姓名:
学 号:
指导教师:
完成日期:
基于STM32的无线通信系统设计
课程设计
计算机科学与技术学院
计算机科学与技术专业
I
ARM
目录
课程设计说明书 ............................................................................................................................................................. I
课程设计任务书 ............................................................................................................................................................ 2
1.
课程设计题目 ................................................................................................................................................................ 3
2.
课程设计目的 ................................................................................................................................................................ 3
3.
课程设计内容 ............................................................................................................................................................ 3
3.1
硬件资源 ................................................................................................................................................................. 3
3.2软件资源 .................................................................................................................................................................. 8
3.3
调试环境准备与使用 ............................................................................................................................................ 11
3.4
系统设计步骤 ....................................................................................................................................................... 12
3.4.1需求分析 ................................................................................................................................................... 12
3.4.2概要设计 ................................................................................................................................................... 12
3.4.3详细设计 ................................................................................................................................................... 16
3.4.4
系统实现及调试 ...................................................................................................................................... 20
3.4.5
功能测试 .................................................................................................................................................. 40
3.4.6
系统评价(结果分析) ......................................................................................................................... 41
3.5.结论(体会) ..................................................................................................................................................... 42
3.6.参考文献 ............................................................................................................................................................. 42
课程设计指导教师评语 .................................................................................................................................................. 43
II
山东建筑大学计算机科学与技术学院
1
课程设计任务书
设计题目
班 级
基于STM32的无线通信系统设计
学 号
指导教师
已知技术
参数和设
计要求
技术参数:
基于Cortex-M3内核的奋斗STM32开发板,无线射频收发器
nRF24L01P工作于2.4GHz频段,STM32和nRF24L01P之间采用SPI
接口方式,嵌入式操作系统平台采用uC/OS-II。
设计要求:
用STM32开发板和nRF24L01扩展板设计一个基于uC/OS-II的
无线通信系统,能够实现两个无线节点间的数据收发。
设计内容:
1. 编写STM32和nRF24L01P的初始化程序。
2. 将uC/OS-II移植至 STM32。
3. 设计简单的无线通信协议,编写无线通信任务和射频收发
中断服务子程序。
设计步骤:
1.uC/OS-II任务划分及概要设计,ISR的功能设计。
2.编写 STM32和nRF24L01P的初始化程序,调试STM32的片
内定时器模块,编写基于nRF24L01P模块的数据收发ISR。
3.编写与移植相关的几个函数,将uC/OS-II移植至 STM32。
4.拟定通信协议,编写无线通信任务。
5.利用两套STM32开发板和nRF24L01扩展板调试上述功能,
总结分析,撰写课程设计说明书。
1、奋斗STM32开发版资源及应用:10学时
2、《Cortex M3权威指南》、《STM32F10X参考手册》、《STM32固
件库手册》:20学时
设计内
容与步
骤
设计工作计
3、MDK安装及使用:5学时
划与进度安
4、概要设计:15学时
排
5、
uC/OS-II
移植及所用外设的驱动程序编写:10学时
6、无线通信任务编程及调试:15学时
7、撰写课程设计说明书:15学时
设计考核
要求
1、考勤20%
2、课程设计说明书50%。
3、成果演示30%
2
1. 课程设计题目
基于STM32的无线通信系统设计
2. 课程设计目的
《ARM课程设计》是计算机科学与技术专业的专业限定选修实践课程,是学习《嵌入式
系统设计》课程后必要的实践教学环节。通过本课程设计使学生加深理解、巩固课堂教学和
平时实验内容,使学生初步具备嵌入式应用系统分析、系统设计、系统实现与测试的实际能
力,强化学生的实践意识、提高动手能力,发挥学生的想象力和创新能力,从而实现课程教
学目标。提高综合运用所学知识进行系统分析、设计的能力。加深对嵌入式软件开发流程以
及项目开发步逐的认识,进一步熟悉UC/OS-II的一直与使用,进一步熟悉UCGUI的使用,
提高嵌入式软件开发所必须的技能。
本课程设计主要培养学生在嵌入式系统设计方面的能力。通过本课程的学习和实践,学
生应能在嵌入式系统组成形式、构造方法、设计流程以及基于集成开发环境调试嵌入式系统
的方法等方面得到锻炼,在硬件系统设计(整合)、操作系统移植、应用程序编写等方面得到
全面训练。
3. 课程设计内容
3.1 硬件资源
基于奋斗STM32开发板,完成<基于STM32的无线通信系统设计>的设计及调试。系统涉及
的硬件资源主要有:
(1) 电源模块
AMS1117-3.3(N1)输入+5V,提供3.3V 的固定电压输出,为了降低电磁干扰,C1-C5 为
CPU 提供BANK 电源(VCC:P50、P75、P100、P28、P11 GND:P49、P74、P99、P27、P10)
滤波。CPU 的模拟输入电源供电脚VDDA(P22)通过L1 22uH 的电感与+3.3V VDD 电压连接,
CPU 的模拟地VSSA(P19)及VREF-(P20)通过R1 0 欧电阻与GND 连接。VREF+(P21)采用
3
VDDA(P22)电源基准。 RT9166-2.5(N2)和RT9166-2.8(N3)输入+5V,提供2.5V 及2.8V 的
固定电压输出,为MP3 电路VS1003 提供所需的电压。为RTC 的备份电源采用V1 3.3V 锂离
子片状电池,如图3.1。
图3.1
(2) 复位时钟模块
外部晶体/陶瓷谐振器(HSE)(P12、P13):B1:8MHz 晶体谐振器,C8,C9 谐振电容选
择10P。系统的时钟经过PLL 模块将时钟提高到72MHz。
低速外部时钟源(LSE)(P8、P9):B2: 32.768KHz 晶体谐振器。C10,C11 谐振电容选
择10P。注意: 根据 ST 公司的推荐, B2 要采用电容负载为6P 的晶振,否则有可能会出
现停振的现象,时钟模块如图3.2所示。
4
图3.2
(3) 主控芯片
采用STM32F103VET6 作为开发板的MCU 平台。这个MCU 是STM32F103里的高容量芯
片, 具有512K 字节的内部FLASH,64K 字节的SRAM, 外设资源有全速USB Device,SDIO,
SPI,I2C,I2S,FSMC,定时器,USART,ADC,DAC,CAN 等接口,如图3.3所示。
图3.3
(4) LCD液晶显示模块
5
LCD显示模块采用STM32 的FSMC 接口模式。显示速度更快。3 寸屏, 分辨率240X400,
64K 色,数据接口16 位,背光源是4 LED 并联模式, 背光驱动采用白光驱动器提供背光用
的横流源, 使背光更加均匀,背光明暗控制采用TTL 电平或者PWM 模式控制。屏上带电阻
式触摸屏, 模块板上带SPI 控制方式的触摸屏控制电路,如图3.4所示。
图3.4
(5) 串行接口
拥有 1 路RS-232 接口,CPU 的PA9-US1-TX(P68)、PA10-US1-RX(P69)通过MAX3232
实现1 路RS-232 接口,分别连接在XS5 和XS17 接口上。 USART1 在系统存储区启动模式
下,可以通过该口通过PC 对板上的CPU 进行ISP,该口也可作为普通串口功能使用, XS6
接口作为TTL 异步通信接口USART2 的接口,在一些应用的调试上有作用,比如通过XS6连
接GPS OEM 板, 可以接收GPS 的协议数据。串行接口如图3.5所示。
USART1 地址:0x4001 3800 - 0x4001 3BFF
USART2 地址:0x4000 4400 - 0x4000 47FF
图3.5
6
(6) NRF24L01 模块简介
本实验采用的无线模块芯片型号为 NRF24L01+,是工作在 2.4~2.5GHz频段的,具备自
动重发功能,6 个数据传输通道,最大无线传输速率为2Mbits。MCU 可与该芯片通过 SPI 接
口访问芯片的寄存器进行配置,模块规格如图3.6所示。
图3.6
SPI写操作
图3.7
SPI读操作
图3.8
7
3.2软件资源
(1) 操作系统
A. 操作系统介绍
本设计所使用的UC/OS-II操作系统版本号为2.85,是一种可移植的,可植入
ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理
器、微控制器和数字信号处理器μC/OS-II是一种可移植的,可植入ROM的,可裁
剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器
和数字信号处理器;最小编译内核可达到2KB,结构精简,硬件要求低。
B. 目录结构
(a) UC-OS-II/Port
在此目录下包含三个文件,OS_CPU_C.C,OS_DBG.C,OS_CPU_;
1. 在OS_CPU_C.C中,定义了系统初始化,系统滴答,系统堆栈初始化等钩
子函数函数,其中,除了系统堆栈初始化是“可重入的”,其他函数都是
不可冲入函数,在执行期间必须关闭中断,否则系统将会出现不可预料
的错误。
2. 在OS_DBG.C中,声明了调试相关的数据结构,以及全局的数据结构配置
声明数据信息,以及系统调试初始化函数;
3. 在OS_CPU_中,使用arm汇编程序完成了全局中断的保存于回复,
最高就绪态的执行,系统上下文切换,系统异常挂起以及进入异常的堆
栈操作等函数;
(b) UC-OS-II/CPU
在此目录下仅有CPU_这一个文件,通篇使用arm汇编完成;主要操作
有中断的使能与清除;临界区操作(进出临界区);
(c) UC-OS-II/Source
在此目录下是操作系统的平台无关性源码,保存了系统核心代码、邮箱,内
存管理,信号量,消息队列,临界资源控制,时间控制等操作系统的各种高
级应用API接口函数,是操作系统的主要功能实现部分;
C. 修改内容
8
在通过以上的了解之后,UC-OS-II系统的源码结构十分清晰,在此只需要修
改UC-OS-II/Port,UC-OS-II/CPU这两个文件中的少量代码即可(细节将在详细设
计中介绍)。
(2) 固件库
stm32f10x_stdperiph_lib,版本为3.5.0,系统库的结构如图3.9所示:
图3.9
CMSCS文件夹内包含的内容与cpu内核和cpu启动相关的文件,
stm32F10x_stdperiph_driver文件内包含了stm32f10x系列所有外设的驱动库;
stm32f10x_stdperiph_example内包含了多个关于本系列芯片的一些例程;
stm32f10x_stdperiph_templete内包含了多种开发平台的模板;最下面的chm文件为关于固
件库的使用说明;
A. MSICS文件,如图3.10所示:
图3.10
core_m3.c为内核相关源码;start_up_.s为stm32f10x高容量系列的启动
文件;system_stm32f10x.c为系统时钟和cpu设置相关配置的源码;
B. stm32F10x_stdperiph_driver
这个文件夹内容如图3.11,包含两个部分,为库的外设驱动源码文件夹,inc中保存头
文件,src保存相关外设的源文件。
9
图3.11
图3.12所示的是外设驱动库的头文件的内容:
图3.12
图3.13所示的是外设驱动库的C文件内容:
图3.13
在本设计中仅使用FSMC,GPIO,RCC,MSIC,EXTI,SPI六个部分;因此只需添加这三个原
文件即可;其中FSMC用来做液晶显示驱动;RCC为操作系统提供systick;MSIC提供了中断
相关的函数;GPIO用来做USB的开关控制;EXTI使用外部中断;SPI提供SPI总线操作,为
NRF24C01和触摸屏提供支持;因此以上部分必须添加;头文件在工程设置中C/C++现象卡中
的includePATH里面选择;
10
(3) UCGUI
uC/GUI是Micrium公司研发的通用的嵌入式用户图像界面软件。他给任何使用图像LCD
的应用程序提供单独于处理器和LCD控制器之外的有效的图形用户接口。能够应用于单一任
务环境,也能够应用于多任务环境中。uC/GUI能够应用于任何LCD控制器和CPU的任何尺寸
的物理显示或模拟显示中。
在此,使用的UCGUI已经封装成库文件,所有的调用接口可以在GUI.h等头文件里面看
到。
用户应用程序只需描述关于窗口的数据结构,GUI显示初始化函数,回调函数,以及用
户界面任务函数四个部分;进行显示任务设计时可以借助UCGUIBulider,通过图形界面设计
产生比较准确的界面布局数据,在本设计中,由于涉及到较多的按键,因此UCGUIBulider只
能编辑到BUTTON9,需要注意的是GUI.H里面定义了用户自定义ID,可以借助这个ID在基础
上增加数字实现 大范围ID定义。
3.3 调试环境准备与使用
(1) MDK编译调试环境安装
MDK安装:首先安装MDK,是常规安装,next,agree。。。。最后选择不安装ULINK
等;安装完毕后,以管理员身份运行keil,在file-》lisenceManagement拷给CID,然后打
开破解软件,拷贝CID,generation拷贝lisence码至keil的lisenceManagement内的license
栏,add添加lisence看到2020年的使用期限则破解成功;
(2) JLINK驱动安装
JLINK安装与常规软件安装无异,最后可以不建立桌面快捷方式和菜单
启动选项;
(3) MDK建立工程
(4) MDK项目属性设置
(5) 使用MDK调试工程
(6) 使用MDK下载运行
11
3.4 系统设计步骤
3.4.1需求分析
(1) 本设计需要实现功能:
编写STM32和nRF24L01P的初始化程序。
将uC/OS-II移植至 STM32。
设计简单的无线通信协议,编写无线通信任务和射频收发中断服务子程序。
(2) 性能价格要求:
A. 在开发板固有硬件资源上尽量不增加硬件资源;选择免费开源嵌入式
操作系统;
B. 使用操作系统,提高任务调度,资源管理,系统稳定性;使用中断提
高响应速度。
(3) 热设计要求:
开发板功耗相对较低,发热元器件分布为分散,不需要其他措施来提高散热能力;
(4) 信息安全要求:
本设计为实验产品,暂不考虑在PC机与开发板通信过程中增加加密模块;
如果是在工程项目中,有必要开率增加通信加密模块(AES或者LBLock都可考虑)。
3.4.2概要设计
(1)软件结构图
图形输入输出界面和无线收发任务
uCOSII实时操作系统
ST库 NRF驱动
uCGUI库文件
LCD驱动
图3.14
(2)程序流程图
12
开始
底层驱动初始化
系统时钟、中断向量、LED指示灯、串口、
uCOS操作系统、uCGUI、触摸屏初始化
检测无线模块连接情况
绘制搜索无线模块界面
否
NRF模块是否连接
是
初始化NRF无线模块
配置NRF为接收模式
绘制输入输出界面
是
是否有输入
接收数据,并将数据
显示在液晶屏上
否
是否有发送请求
否
是
13
NRF切换成发送模式
发送数据
否
否
发送完成后是
否接到响应
是否达到最大
发送次数
是
是
NRF切换至接收模式
14
(2)任务和ISR描述
A.任务描述
编
号
1
2
3
4
任务名称
开始任务
用户界面
触摸输入
空闲
英文简称
App_TaskStart
AppTaskUserIF
AppTaskKbd
Idle
优先
级
2
5
4
10
堆栈容量
(BYTE)
128
256
512
16
任务描述
创建其他子任务
创建输入输出窗体
检测触摸屏输入
空闲任务
B. ISR描述
编号
1
2
ISR名称
复位
英文简称
RST_ISR
优先级
1
2
ISR描述
上电复位,看门狗复位,按键复位
系统时钟
SysTickHandler
外部中断0
EXTI0_IRQHandl
er
系统时钟中断
3
组优先级0,(NRF24L01中断)
次优先级1
(3)接口设计
A. 用户接口HMI
硬件:TFT3.2寸液晶屏
控制器ILI9341
TFT触摸控制器TSC2046
软件:uCGUI窗体
文本编辑框控件,显示要发送的内容
TXT文本显示控件,显示接收到的内容
按键控件,send clear发送和清空按键,大小写转换按键和数字和字母组合按键。
B. 内部接口
UART接口:
用于串口调试。
Uart1管脚配置
管脚名称
Uart_TX
Uart_RX
Uart1模式配置
波特率:115200
数据位:8
停止位:1
校验位:无
管脚名称
GPIOA GPIO_Pin_9
GPIOA GPIO_Pin_10
输入输出模式
复用推完输出模式
浮空输入模式
15
SPI接口:
NRF24L01模块通信接口SPI2管脚配置
管脚名称 对应管脚管脚
SCK GPIOB GPIO_Pin_13
MISO GPIOB GPIO_Pin_14
MOSI GPIOB GPIO_Pin_15
CE GPIOC GPIO_Pin_6
CS GPIOB GPIO_Pin_0
IRQ GPIOA GPIO_Pin_0
NRF24L01模块通信接口SPI2管脚模式配置
双线全双工
主模式
数据大小8位
上升沿采样
高位在前
输入输出模式
复用推挽输出模式
通用推挽输出模式
上拉输入模式
3.4.3详细设计
(1)数据存储空间分配,包括每种数据的名称、作用域、数据类型、占用物理空间大小、涉
及的任务或ISR
数据名称
Rx_Succ
描述 作用域 数据类型
unsigned char
大小
1B
涉及的任务或ISR
AppTaskUserIF任务
和EXTI0_IRQn中断
unsigned char
unsigned char
unsigned char
unsigned char
接收成功标全局
志
TX_ADDRESS0-5 通道地址0-5 全局
rx_buf
tx_buf
status_buf
接收缓存区
发射缓存区
状态缓冲区
全局
全局
全局
5B
32B
32B
32B
EXTI0_IRQn中断
AppTaskUserIF任务
AppTaskUserIF任务
AppTaskUserIF任务
和EXTI0_IRQn中断
nrf_baud
nrf_Pipe
波特设置 全局 unsigned char
unsigned char
1B
1B
AppTaskUserIF任务
AppTaskUserIF任务 发射通道选全局
择
nrf_Pipe_r 接收通道选全局
择
unsigned char 1B EXTI0_IRQn中断
(2)主要任务及中断服务子程序的流程图3.14:
16
执行main()
系统时钟的设置
RCC_Configuration
()
GPIO_Configur
ation()
NVIC_Configur
ation()
tp_config()
显示器接口
FSMC进行配置
外设初始化BSP_Init()
ucosII内核初始化
OSInit()
禁止CPU的中断
-CPU_IntDis()
图3.14
建立主任务,该任务是为了在内核启动后,建立另外2个用户任务, 并清0节拍计数器, 启
动ucOSII内核。主任务的任务名为App_TaskStart, 主任务有自己的堆栈, 堆栈尺寸为
APP_TASK_START_STK_SIZE*4(字节), 然后执行ucosII内部函数OSTimeSet(0),将节拍计
数器清0,节拍计数器范围是0-4294967295,对于节拍频率100hz时, 每隔497天就重新计
数, 调用内部函数OSStart(),启动ucosII内核, 此时ucosII内核开始运行。对任务表
进行监视,主任务因为已经处于就绪状态,于是开始执行主任务App_TaskStart(),uCOSII
的任务结构规定必须为无返回的结构,也就是无限循环模式如3.15所示
SPI2_NRF24L01_Init(void)
使能SPI2外设时钟
配置 SPI2 引脚
配置SPI2 NRF24L01+片选
SPI2
配置NRF24L01+ 模式选择
配置NRF24L01+ 中断信号产生
连接到 PA0
17
禁止SPI2 NRF24L01+的片选。
SPI2 配置
使能SPI2
图3.15
通过SPI2 发送一个字节的数据:
否
返回读出的数据
是
接收缓冲区是否
是空
否
通过SPI2外设发出数据
是
发送缓冲区是否
是空
开 始
图3.16
void EXTI0_IRQHandler(void)为 NRF24L01 发送及接收中断响应程序:
判断是否产生了
EXTI0中断
恢复全局中断标志
保存全局中断
标志,关总中断
开 始
18
结 束
执行一次任务切换
清除07寄存器标志 进入接收模式
读取状态寄存其来判断数据
判断是否接收到
数据
是
否
否
发射达到最大复
发次数
是
清除发送缓冲区
否
判断是否是PA0
线变低
是
否
是
清除EXTI0上的中断标志
图3.17
(3)液晶显示器界面含有发送数据、接收数据、键盘,通过点击按键显示所输入内容,点击
发送后,显示器接收数据内显示所发送内容,另外一块液晶显示器接收数据后,显示所发送
内容,实现无线通信功能。 其中所涉及的函数有GUI_WIDGET_CREATE_INFO(定义了对
话框资源列表)、GUI_WIDGET_CREATE_INFO(定义了对话框资源列表)、
_cbCallback(WM_MESSAGE * pMsg)(ucgui回调函数,是作为对话框动作响应的函数)、
Fun(void)(显示及处理界面)。
19
3.4.4 系统实现及调试
(1)主程序
int main(void)
{
// CPU_INT08U os_err;
/* 禁止所有中断 */
CPU_IntDis();
/* ucosII 初始化 */
OSInit();
/* 硬件平台初始化 */
BSP_Init();
//建立主任务, 优先级最高 建立这个任务另外一个用途是为了以后使用统计任务
// os_err =
OSTaskCreate((void (*) (void *)) App_TaskStart, //指向
任务代码的指针
(void *) 0, //
任务开始执行时,传递给任务的参数的指针
(OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE -
1], //分配给任务的堆栈的栈顶指针 从顶向下递减
(INT8U) APP_TASK_START_PRIO);
//分配给任务的优先级
OSTimeSet(0); //ucosII的节拍计数器清0 节拍计数器是0-4294967295
OSStart(); //启动ucosII内核
return (0);
}
(2)任务设计
/****************************************************************************
* 名 称:static void App_TaskStart(void* p_arg)
* 功 能:开始任务建立
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:无
****************************************************************************/
static void App_TaskStart(void* p_arg)
{
(void) p_arg;
//初始化ucosII时钟节拍
OS_CPU_SysTickInit();
//使能ucos 的统计任务
20
#if (OS_TASK_STAT_EN > 0)
OSStatInit(); //----统计任务初始化函数
#endif
App_TaskCreate(); //建立其他的任务
while (1)
{
/* 100ms间隔LED闪烁 */
Led_ON();
OSTimeDlyHMSM(0, 0, 0, 100);
Led_OFF();
OSTimeDlyHMSM(0, 0, 0, 100);
}
}
/****************************************************************************
* 名 称:static void App_TaskCreate(void)
* 功 能:建立其余任务的函数
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:无
****************************************************************************/
static void App_TaskCreate(void)
{
/* 建立用户界面任务 */
OSTaskCreateExt(AppTaskUserIF, //指向
任务代码的指针
(void *)0, //任务开始
执行时,传递给任务的参数的指针
(OS_STK *)&AppTaskUserIFStk[APP_TASK_USER_IF_STK_SIZE-1], //分
配给任务的堆栈的栈顶指针 从顶向下递减
APP_TASK_USER_IF_PRIO, //分配
给任务的优先级
APP_TASK_USER_IF_PRIO, //预备
给以后版本的特殊标识符,在现行版本同任务优先级
(OS_STK *)&AppTaskUserIFStk[0], //指向
任务堆栈栈底的指针,用于堆栈的检验
APP_TASK_USER_IF_STK_SIZE, //
指定堆栈的容量,用于堆栈的检验
(void *)0, //指向
用户附加的数据域的指针,用来扩展任务的任务控制块
OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR); //
选项,指定是否允许堆栈检验,是否将堆栈清0,任务是否要
//进行浮点运算等等。
21
/* 建立触摸驱动任务 */
OSTaskCreateExt(AppTaskKbd,
(void *)0,
(OS_STK *)&AppTaskKbdStk[APP_TASK_KBD_STK_SIZE-1],
APP_TASK_KBD_PRIO,
APP_TASK_KBD_PRIO,
(OS_STK *)&AppTaskKbdStk[0],
APP_TASK_KBD_STK_SIZE,
(void *)0,
OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);
}
/****************************************************************************
* 名 称:static void AppTaskUserIF (void *p_arg)
* 功 能:用户界面任务
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:无
****************************************************************************/
static void AppTaskUserIF (void *p_arg)
{
(void)p_arg;
GUI_Init(); //ucgui初始化
while(1)
{
Fun(); //界面主程序
}
}
/****************************************************************************
* 名 称:static void AppTaskKbd (void *p_arg)
* 功 能:触摸屏坐标获取
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:无
****************************************************************************/
static void AppTaskKbd (void *p_arg)
{
(void)p_arg;
while(1)
{
/* 延时10ms会读取一次触摸坐标 */
OSTimeDlyHMSM(0,0,0,10);
22
GUI_TOUCH_Exec();
}
}
(3)中断服务子程序
void SysTickHandler(void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); //保存全局中断标志,关总中断/* Tell uC/OS-II that we are
starting an ISR*/
OSIntNesting++; //OSSemPost(NMEA_MBOX);
OS_EXIT_CRITICAL(); //恢复全局中断标志
OSTimeTick(); /* Call uC/OS-II's OSTimeTick(),在os_core.c文件里定义,主要
判断延时的任务是否计时到*/
OSIntExit(); //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一
次任务切换
}
void EXTI0_IRQHandler(void)
{
unsigned char status;
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); //保存全局中断标志,关总中断 Tell uC/OS-II that we are
starting an ISR
OSIntNesting++;
OS_EXIT_CRITICAL(); //恢复全局中断标志
if(EXTI_GetITStatus(EXTI_Line0) != RESET) //判断是否产生了EXTI0中断
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0){ //判断是否是PA0线变低
status = SPI_Read(READ_REG1+STATUS); // 读取状态寄存其来判断数据接
收状况
if(status & 0x40) // 判断是否接收到数据
{
SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH); //从接收缓冲区里读
出数据
if((status & 0x0e) <= 0x0a)
{
nrf_Pipe_r=(status&0x0e)>>1; //读出是在哪个通道接收
的
}
else
{
nrf_Pipe_r=0;
}
23
Rx_Succ = 1; //读取数据完成标志
/* 根据读出的接收通道号,将相应信息写入状态文本缓冲区 */
if(nrf_Pipe_r==0) memcpy(status_buf, "Pipe 0 Recive OK! ", 20);
else if(nrf_Pipe_r==1) memcpy(status_buf, "Pipe 1 Recive OK! ", 20);
else if(nrf_Pipe_r==2) memcpy(status_buf, "Pipe 2 Recive OK! ", 20);
else if(nrf_Pipe_r==3) memcpy(status_buf, "Pipe 3 Recive OK! ", 20);
else if(nrf_Pipe_r==4) memcpy(status_buf, "Pipe 4 Recive OK! ", 20);
else if(nrf_Pipe_r==5) memcpy(status_buf, "Pipe 5 Recive OK! ", 20);
}
else if((status &0x10) > 0)
{ //发射达到最大复发次数
SPI_RW_Reg(0xe1,0); //清除发送缓冲区
RX_Mode(); //进入接收模式
Rx_Succ=1;
/* 根据发送通道,将相应信息写入状态文本缓冲区 */
if(nrf_Pipe==0) memcpy(status_buf, "Pipe 0 NO ACK! ", 20);
else if(nrf_Pipe==1) memcpy(status_buf, "Pipe 1 NO ACK! ", 20);
else if(nrf_Pipe==2) memcpy(status_buf, "Pipe 2 NO ACK! ", 20);
else if(nrf_Pipe==3) memcpy(status_buf, "Pipe 3 NO ACK! ", 20);
else if(nrf_Pipe==4) memcpy(status_buf, "Pipe 4 NO ACK! ", 20);
else if(nrf_Pipe==5) memcpy(status_buf, "Pipe 5 NO ACK! ", 20);
}
else if((status &0x20) > 0)
{ //发射后收到应答
SPI_RW_Reg(0xe1,0); //清除发送缓冲区
RX_Mode(); //进入接收模式
Rx_Succ=1;
/* 根据发送通道,将相应信息写入状态文本缓冲区 */
if(nrf_Pipe==0) memcpy(status_buf, "Pipe 0 Send OK! ", 20);
else if(nrf_Pipe==1) memcpy(status_buf, "Pipe 1 Send OK! ", 20);
else if(nrf_Pipe==2) memcpy(status_buf, "Pipe 2 Send OK! ", 20);
else if(nrf_Pipe==3) memcpy(status_buf, "Pipe 3 Send OK! ", 20);
else if(nrf_Pipe==4) memcpy(status_buf, "Pipe 4 Send OK! ", 20);
else if(nrf_Pipe==5) memcpy(status_buf, "Pipe 5 Send OK! ", 20);
}
SPI_RW_Reg(WRITE_REG1+STATUS, status); //清除07寄存器标志
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除EXTI0上的中断标志
}
OSIntExit(); //在os_core.c文件里定义,如果有更高优先级的任务就绪了,
则执行一次任务切换
}
(4)界面实现设计
24
void Fun(void);
extern void RX_Mode(void);
extern void TX_Mode(void);
extern void NRF24L01_TXBUF(uint8_t* data_buffer, uint8_t Nb_bytes);
int8_t Shift = 0;
unsigned char text_buf[32] = "";
/* ucgui类型定义*/
WM_HWIN hWin;
WM_HWIN hListBox[8];
WM_HWIN text1,text2,text3,bt[33],edit1,edit2;
GUI_COLOR DesktopColorOld;
const GUI_FONT* pFont = &GUI_Font8x13_1;
const GUI_FONT* pFont18 = &GUI_FontComic18B_1;
/* 定义了对话框资源列表 */
static const GUI_WIDGET_CREATE_INFO aDialogCreate[] = {
{ FRAMEWIN_CreateIndirect, "NRF24L01P", 0, 0, 0, 240, 400,
FRAMEWIN_CF_ACTIVE },
{ BUTTON_CreateIndirect, "SEND", GUI_ID_BUTTON0, 0, 316, 120, 55 },
{ BUTTON_CreateIndirect, "CLEAR", GUI_ID_BUTTON1, 120, 316, 120, 55 },
{ EDIT_CreateIndirect, "", GUI_ID_EDIT1, 0, 25, 230, 35,
EDIT_CF_LEFT, 50 },
{ EDIT_CreateIndirect, "", GUI_ID_EDIT2, 0, 85, 230, 35,
EDIT_CF_LEFT, 50 },
{ TEXT_CreateIndirect, "Send Text Area", GUI_ID_TEXT0, 1, 2, 230,
25, TEXT_CF_LEFT },
{ TEXT_CreateIndirect, "Receive Text Area ", GUI_ID_TEXT1, 1, 62, 230,
25, TEXT_CF_LEFT },
{ BUTTON_CreateIndirect, "Q", GUI_ID_BUTTON2, 0, 150,24, 30, 0,0},
{ BUTTON_CreateIndirect, "W", GUI_ID_BUTTON3, 24, 150,24,30, 0,0},
25
{ BUTTON_CreateIndirect, "P", GUI_ID_BUTTON11, 216,150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "O", GUI_ID_BUTTON10, 192,150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "I", GUI_ID_BUTTON9, 168,150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "Y", GUI_ID_BUTTON7, 120,150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "U", GUI_ID_BUTTON8, 144,150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "T", GUI_ID_BUTTON6, 96, 150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "R", GUI_ID_BUTTON5, 72, 150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "E", GUI_ID_BUTTON4, 48, 150,24, 30,
0,0},
{ BUTTON_CreateIndirect, "A", GUI_ID_BUTTON12, 10, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "S", GUI_ID_BUTTON13, 34, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "D", GUI_ID_BUTTON14, 58, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "F", GUI_ID_BUTTON15, 82, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "G", GUI_ID_BUTTON16, 106, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "H", GUI_ID_BUTTON17, 130, 182,24, 30,
0,0},
26
{ BUTTON_CreateIndirect, "J", GUI_ID_BUTTON18, 154, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "K", GUI_ID_BUTTON19, 178, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "L", GUI_ID_BUTTON20, 202, 182,24, 30,
0,0},
{ BUTTON_CreateIndirect, "Z", GUI_ID_BUTTON21, 34, 214,24, 30,
0,0 },
{ BUTTON_CreateIndirect, "X", GUI_ID_BUTTON22, 58, 214,24, 30,
0,0},
{ BUTTON_CreateIndirect, "C", GUI_ID_BUTTON23, 82, 214,24, 30,
0,0},
{ BUTTON_CreateIndirect, "V", GUI_ID_BUTTON24, 106, 214,24, 30,
0,0},
{ BUTTON_CreateIndirect, "B", GUI_ID_BUTTON25, 130, 214,24, 30,
0,0},
{ BUTTON_CreateIndirect, "N", GUI_ID_BUTTON26, 154, 214,24, 30,
0,0},
{ BUTTON_CreateIndirect, "M", GUI_ID_BUTTON27, 178, 214,24, 30,
0,0},
{ BUTTON_CreateIndirect, "Shift", GUI_ID_BUTTON28, 0, 214,34, 30,
0,0},
{ BUTTON_CreateIndirect, "1", GUI_ID_BUTTON29, 0, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "2", GUI_ID_BUTTON30, 24, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "3", GUI_ID_BUTTON31, 48, 246,24, 30,
0,0},
27
{ BUTTON_CreateIndirect, "4", GUI_ID_BUTTON32, 72, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "5", GUI_ID_BUTTON33, 96, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "6", GUI_ID_BUTTON34, 120, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "7", GUI_ID_BUTTON35, 144, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "8", GUI_ID_BUTTON36, 168, 246,24, 30,
0,0},
{ BUTTON_CreateIndirect, "9", GUI_ID_BUTTON37, 192, 246,24, 30,
0,0},
{ TEXT_CreateIndirect, "status", GUI_ID_TEXT2, 1, 120, 240, 25,
TEXT_CF_HCENTER },
};
/****************************************************************************
* 名 称:static void _cbCallback(WM_MESSAGE * pMsg)
* 功 能:ucgui回调函数,是作为对话框动作响应的函数
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:
****************************************************************************/
static void _cbCallback(WM_MESSAGE * pMsg)
{
unsigned char text_buf[1] = "";
int NCode, Id;
switch (pMsg->MsgId)
{
case WM_NOTIFY_PARENT: //通知父窗口有事件在窗口部件上发生
Id = WM_GetId(pMsg->hWinSrc); //获得对话框窗口里发生事件的部
件的ID
NCode = pMsg->Data.v; //通知代码
switch (NCode)
{
case WM_NOTIFICATION_RELEASED: //窗体部件动作被释放
if (Id == GUI_ID_BUTTON1)
28
{ //按键CLEAR被松开
memcpy(status_buf, "", 20); //清空状态文本缓冲区
memcpy(rx_buf, "", 32); //清空接收文本缓冲区
TEXT_SetText(text3,(const char *)status_buf); //清空状态文本框
EDIT_SetText(edit2,(const char *)rx_buf); //清空接收字符编辑框
memcpy(tx_buf, "", 32); //清空发送文本缓冲区
NRF24L01_TXBUF(tx_buf,32); //将发送字符缓冲区的字符通过
NRF24L01发送出去
EDIT_SetText(edit1,(const char *)tx_buf); //清空接收字符编辑框
}
else if (Id == GUI_ID_BUTTON0)
{ //按键SEND 被松开
// memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32); //将32字节
的文本拷贝到发送文本缓冲区
// memcpy(tx_buf, "", 32); //清空发送文本缓冲区
memcpy(rx_buf, "", 32); //清空接收文本缓冲区
memcpy(status_buf, "", 20); //清空状态文本缓冲区
EDIT_SetText(edit2,(const char *)rx_buf); //清空接收字符编辑框
NRF24L01_TXBUF(tx_buf,32); //将发送字符缓冲区的字符通过
NRF24L01发送出去
memcpy(tx_buf, "", 32); //清空发送文本缓冲区
EDIT_SetText(edit1,(const char *)tx_buf); //清空接收字符编辑框
TEXT_SetText(text3,(const char *)status_buf); //清空状态文本框
}
else if(Id == GUI_ID_BUTTON28)
{
if(Shift==0) Shift = 1;
else Shift = 0;
}
else if(Id == GUI_ID_BUTTON2)
{
if(Shift==0) memcpy(text_buf,"q", 1);
else memcpy(text_buf,"Q", 1);
strcat((char *)tx_buf,(const char *)text_buf);
EDIT_SetText(edit1,(const char *)tx_buf);
}
。。。。。。
}
else if(Id == GUI_ID_BUTTON29)
{
memcpy(text_buf,"1", 1);
strcat((char *)tx_buf,(const char *)text_buf);
29
EDIT_SetText(edit1,(const char *)tx_buf);
}
。。。。。。
break;
default: break;
}
default:
WM_DefaultProc(pMsg); //默认程序来处理消息
break;
}
}
/****************************************************************************
* 名 称:void Fun(void)
* 功 能:显示及处理界面
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:无
****************************************************************************/
void Fun(void)
{
GUI_CURSOR_Show(); //打开鼠标图形显示
/* 建立对话框时,包含了资源列表,资源数目, 并且指定了用于动作响应的回调函数 */
hWin = GUI_CreateDialogBox(aDialogCreate, GUI_COUNTOF(aDialogCreate),
_cbCallback, 0, 0, 0);
FRAMEWIN_SetFont(hWin, &GUI_FontComic18B_1); //对话框字体设置
FRAMEWIN_SetClientColor(hWin, GUI_WHITE); //对话框的窗体颜色是
黑色
// memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32); //将长度为32字节的
发送字符串拷贝到发送缓冲区
memcpy(tx_buf, "", 32);
memcpy(rx_buf, "", 32); //将接收缓存区清空
text1 = WM_GetDialogItem(hWin, GUI_ID_TEXT0); //获得对话框里
GUI_ID_TEXT0项目(文本框Send Text Area)的句柄
text2 = WM_GetDialogItem(hWin, GUI_ID_TEXT1); //获得对话框里
GUI_ID_TEXT1项目(文本框Receive Text Area)的句柄
text3 = WM_GetDialogItem(hWin, GUI_ID_TEXT2); //获得对话框里
GUI_ID_TEXT2项目(状态字符文本框)的句柄
TEXT_SetFont(text1,pFont); //设置对话框里文本框
Send Text Area的字体
30
TEXT_SetFont(text2,pFont);
Receive Text Area的字体
TEXT_SetFont(text3,pFont);
本框的字体
TEXT_SetTextColor(text1,GUI_GREEN);
Text Area的字体颜色
TEXT_SetTextColor(text2,GUI_GREEN);
Receive Text Area的字体颜色
TEXT_SetTextColor(text3,GUI_RED);
符文本框的字体颜色
edit1 = WM_GetDialogItem(hWin, GUI_ID_EDIT1);
GUI_ID_EDIT1项目(编辑框 发送字符串显示区)的句柄
EDIT_SetFont(edit1,pFont18);
送字符串显示区的字体
EDIT_SetText(edit1,(const char *)tx_buf);
框里编辑框 发送字符串显示区的字符串
edit2 = WM_GetDialogItem(hWin, GUI_ID_EDIT2);
GUI_ID_EDIT2项目(编辑框 接收字符串显示区)的句柄
EDIT_SetFont(edit2,pFont18);
收字符串显示区的字体
EDIT_SetText(edit2,(const char *)rx_buf);
框里编辑框 接收字符串显示区的字符串
bt[0]=WM_GetDialogItem(hWin,GUI_ID_BUTTON0);
GUI_ID_BUTTON0项目(按键SEND)的句柄
bt[1]=WM_GetDialogItem(hWin,GUI_ID_BUTTON1);
GUI_ID_BUTTON0项目(按键CLEAR)的句柄
BUTTON_SetFont(bt[0],pFont);
的字体
BUTTON_SetFont(bt[1],pFont);
的字体
BUTTON_SetTextColor(bt[0],0,GUI_WHITE);
SEND未被按下的字体颜色
BUTTON_SetTextColor(bt[1],0,GUI_WHITE);
未被按下的字体颜色
nrf_Pipe = 0;
置为0
nrf_baud = 0;
2MPS
RX_Mode();
while (1)
{
if(Rx_Succ==1){ //
有效数据
31
//设置对话框里文本框
//设置对话框里状态字符文
//设置对话框里文本框Send
//设置对话框里文本框
//设置对话框里状态字
//获得对话框里
//设置对话框里编辑框 发
//设置对话
//获得对话框里
//设置对话框里编辑框 接
//设置对话
//获得对话框里
//获得对话框里
//设置对话框里按键SEND
//设置对话框里按键CLEAR
//设置对话框里按键
//设置对话框里按键CLEAR
//NRF24L01初始发射通道设
//NRF24L01速率 初始为
//NRF24L01进入接收模式
当NRF24L01接收到
EDIT_SetText(edit2,(const char *)rx_buf); //将接收缓冲区的字符写
入到接收字符编辑框内
TEXT_SetText(text3,(const char *)status_buf); //将状态文本缓冲区的字符
写入到状态文本框内
Rx_Succ = 0;
}
WM_Exec(); //刷新屏幕
}
}
(5)NRF24L01驱动设计
/****************************************************************************
* Copyright (C), 2013 wccWorkRoot,
*
* 文件名: NRF24L01.c
* 内容简述:
* 2.4G 通信模块NRF24L01+的驱动部分
*
* 文件历史:
* 版本号 日期 作者 说明
* v0.1 2015-10-25 wcc 创建该文件
*
****************************************************************************/
#define NRF_GLOBALS
#include "NRF24L01.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"
#include "globals.h"
void MODE_CE(BYTE a);
void SPI2_NRF24L01_Init(void);
BYTE SPI2_NRF_SendByte(BYTE byte);
BYTE SPI_RW_Reg(BYTE data1, BYTE data2);
BYTE SPI_Write_Buf(BYTE reg, BYTE *pBuf, BYTE bytes);
BYTE SPI_Read(BYTE reg);
BYTE SPI_Read_Buf(BYTE reg, BYTE *pBuf, BYTE bytes);
void RX_Mode(void);
void TX_Mode(void);
void NRF24L01_TXBUF(uint8_t* data_buffer, uint8_t Nb_bytes);
/****************************************************************************
* 名 称:void MODE_CE(BYTE a)
* 功 能:NRF24L01 收/发模式有效选择
* 入口参数:a: 1:NRF24L01 收/发有效 0:关
* 出口参数:无
* 说 明:
32
* 调用方法:MODE_CE(1);
****************************************************************************/
void MODE_CE(BYTE a){ //NRF24L01 MODE-CE
if(a==1) GPIO_SetBits(GPIOC, GPIO_Pin_6); //On
else GPIO_ResetBits(GPIOC, GPIO_Pin_6); //Off
}
/****************************************************************************
* 名 称:void SPI2_NRF24L01_Init(void)
* 功 能:NRF24L01 SPI2接口初始化
* 入口参数:无
* 出口参数:无
* 说 明:
* 调用方法:SPI2_NRF24L01_Init();
****************************************************************************/
void SPI2_NRF24L01_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 ,ENABLE); //使能SPI2外设时钟
/* 配置 SPI2 引脚: SCK, MISO and MOSI(PB13, PB14, PB15) */
GPIO__Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO__Speed = GPIO_Speed_50MHz;
GPIO__Mode = GPIO_Mode_AF_PP; //复用功能(推挽)输出
SPI2
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* 配置SPI2 NRF24L01+片选 PB0 */
GPIO__Pin = GPIO_Pin_0;
GPIO__Speed = GPIO_Speed_50MHz; //输出模式最大速度
50MHz
GPIO__Mode = GPIO_Mode_Out_PP; //通用推挽输出模式
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* 配置NRF24L01+ 模式选择 PC6 */
GPIO__Pin = GPIO_Pin_6; //NRF24L01 MODE-CE
GPIO__Speed = GPIO_Speed_50MHz; //输出模式最大速度
50MHz
GPIO__Mode = GPIO_Mode_Out_PP; //通用推挽输出模式
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* 配置NRF24L01+ 中断信号产生连接到 PA0 */
GPIO__Pin = GPIO_Pin_0; //NRF24L01 IRQ
33
GPIO__Mode = GPIO_Mode_IPU; //上拉输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
//禁止SPI2 NRF24L01+的片选。
NotSelect_NRF();
/* SPI2 配置 */
SPI__Direction = SPI_Direction_2Lines_FullDuplex; //全双工
SPI__Mode = SPI_Mode_Master; //主模式
SPI__DataSize = SPI_DataSize_8b; //8位
SPI__CPOL = SPI_CPOL_Low; //时钟极性 空
闲状态时,SCK保持低电平
SPI__CPHA = SPI_CPHA_1Edge; //时钟相位
数据采样从第一个时钟边沿开始
SPI__NSS = SPI_NSS_Soft; //软件产生
NSS
SPI__BaudRatePrescaler = SPI_BaudRatePrescaler_16; //波特率控
制 SYSCLK/16
SPI__FirstBit = SPI_FirstBit_MSB; //数据高位在前
SPI__CRCPolynomial = 7; //CRC多项
式寄存器初始值为7
SPI_Init(SPI2, &SPI_InitStructure);
/* 使能SPI2 */
SPI_Cmd(SPI2, ENABLE); //SPI_Cmd()函数定义在 #include "stm32f10x_spi.h"
}
/****************************************************************************
* 名 称:BYTE SPI2_NRF_SendByte(BYTE byte)
* 功 能:通过SPI2 发送一个字节的数据。
* 入口参数:byte: 发送的数据
* 出口参数:接收到的字节
* 说 明:
* 调用方法:SPI2_NRF_SendByte(data1);
****************************************************************************/
BYTE SPI2_NRF_SendByte(BYTE byte)
{
/* 循环检测发送缓冲区是否是空 */
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
/* 通过SPI2外设发出数据 */
SPI_I2S_SendData(SPI2, byte);
/* 等待接收数据,循环检查接收数据缓冲区 */
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
/* 返回读出的数据 */
return SPI_I2S_ReceiveData(SPI2);
}
/****************************************************************************
34
* 名 称:unsigned char SPI_RW_Reg(unsigned char data1,unsigned char data2)
* 功 能:通过SPI2 将单字节写入到NRF24L01+指定的寄存器里。
* 入口参数:data1: NRF24L01寄存器
data2: 单字节数据
* 出口参数:接收到的字节
* 说 明:
* 调用方法:SPI_RW_Reg(WRITE_REG1 + EN_AA, 0x3f);
****************************************************************************/
BYTE SPI_RW_Reg(BYTE data1,BYTE data2)
{
BYTE Data = 0;
Select_NRF(); //选择NRF24L01片选
Data = SPI2_NRF_SendByte(data1); //指定NRF24L01寄存器
SPI2_NRF_SendByte(data2); //写入数据
NotSelect_NRF(); //禁止NRF24L01片选
return(Data); //返回NRF24L01 写寄存器的状态信息
}
/****************************************************************************
* 名 称:unsigned char SPI_Write_Buf(BYTE reg, BYTE *pBuf, BYTE bytes)
* 功 能:通过SPI2 将数组里的数据写入到NRF24L01+指定的寄存器里。
* 入口参数:reg: NRF24L01寄存器
pBuf: 数组
bytes: 写入的字节数
* 出口参数:接收到的字节
* 说 明:
* 调用方法:SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS0, TX_ADR_WIDTH);
****************************************************************************/
BYTE SPI_Write_Buf(BYTE reg, BYTE *pBuf, BYTE bytes)
{
BYTE status,byte_ctr;
Select_NRF(); //选择NRF24L01片选
status = SPI2_NRF_SendByte(reg); //指定NRF24L01寄存器
for(byte_ctr=0; byte_ctr { SPI2_NRF_SendByte(*pBuf++); } NotSelect_NRF(); //禁止NRF24L01片选 return(status); //返回NRF24L01 写寄存器的状态信息 } /**************************************************************************** * 名 称:unsigned char SPI_Read(BYTE reg) 35 * 功 能:通过SPI2 将NRF24L01+指定的寄存器里读出一个字节。 * 入口参数:reg: NRF24L01寄存器 * 出口参数:指定NRF24L01寄存器的状态信息 * 说 明: * 调用方法:status=SPI_Read(READ_REG1+STATUS); ****************************************************************************/ BYTE SPI_Read(BYTE reg) { BYTE Data; Select_NRF(); //选择NRF24L01片选 SPI2_NRF_SendByte(reg); //指定NRF24L01寄存器 Data = SPI2_NRF_SendByte(0); //读出数据 NotSelect_NRF(); //禁止NRF24L01片选 return (Data); } /**************************************************************************** * 名 称:unsigned char SPI_Read_Buf(BYTE reg, BYTE *pBuf, BYTE bytes) * 功 能:通过SPI2 将NRF24L01+指定的寄存器里的数据读出指定长度到指定的数组里。 * 入口参数:reg: NRF24L01寄存器 pBuf: 数组 bytes: 长度 * 出口参数:指定NRF24L01寄存器的状态信息 * 说 明: * 调用方法:SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH); ****************************************************************************/ BYTE SPI_Read_Buf(BYTE reg, BYTE *pBuf, BYTE bytes) { BYTE status,i; Select_NRF(); //选择NRF24L01片选 status=SPI2_NRF_SendByte(reg); //读出指定NRF24L01寄存器的状态信息 for(i=0; i { pBuf[i]=SPI2_NRF_SendByte(0); } NotSelect_NRF(); //禁止NRF24L01片选 return(status); //返回指定NRF24L01寄存器的状态信息 } /**************************************************************************** * 名 称:RX_Mode(void) * 功 能:设置NRF24L01+的接收模式 * 入口参数:无 * 出口参数:无 * 说 明:设置了6个接收通道地址,数据宽度32、接收自动应答、6个接收通道使能、 36 * 射频频道0、16位CRC、收发中断、增益0dB等等 * 调用方法:RX_Mode(); ****************************************************************************/ void RX_Mode(void) { MODE_CE(0); SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS0, TX_ADR_WIDTH); //数据通道 0接收地址,最大5个字节, 此处接收地址和发送地址相同 SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P1, TX_ADDRESS1, TX_ADR_WIDTH); //数据通道 1接收地址,最大5个字节, 此处接收地址和发送地址相同 // SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P2, TX_ADDRESS2, TX_ADR_WIDTH); //数据通道 2接收地址,最大5个字节, 此处接收地址和发送地址相同 // SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P3, TX_ADDRESS3, TX_ADR_WIDTH); //数据通道 3接收地址,最大5个字节, 此处接收地址和发送地址相同 // SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P4, TX_ADDRESS4, TX_ADR_WIDTH); //数据通道 4接收地址,最大5个字节, 此处接收地址和发送地址相同 // SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P5, TX_ADDRESS5, TX_ADR_WIDTH); //数据通道 5接收地址,最大5个字节, 此处接收地址和发送地址相同 SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P2, TX_ADDRESS2, 1); //数据通道2接收地址, 5个字节, 高字节与TX_ADDRESS1[39:8]相同,低字节同TX_ADDRESS2[0] SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P3, TX_ADDRESS3, 1); //数据通道3接收地址, 5个字节, 高字节与TX_ADDRESS1[39:8]相同,低字节同TX_ADDRESS3[0] SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P4, TX_ADDRESS4, 1); //数据通道4接收地址, 5个字节, 高字节与TX_ADDRESS1[39:8]相同,低字节同TX_ADDRESS4[0] SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P5, TX_ADDRESS5, 1); //数据通道5接收地址, 5个字节, 高字节与TX_ADDRESS1[39:8]相同,低字节同TX_ADDRESS5[0] SPI_RW_Reg(WRITE_REG1 + RX_PW_P0, TX_PLOAD_WIDTH); // 接收数据通道0有效数据 宽度32 范围1-32 SPI_RW_Reg(WRITE_REG1 + RX_PW_P1, TX_PLOAD_WIDTH); // 接收数据通道1有效数据 宽度32 范围1-32 SPI_RW_Reg(WRITE_REG1 + RX_PW_P2, TX_PLOAD_WIDTH); // 接收数据通道2有效数据 宽度32 范围1-32 SPI_RW_Reg(WRITE_REG1 + RX_PW_P3, TX_PLOAD_WIDTH); // 接收数据通道3有效数据 宽度32 范围1-32 SPI_RW_Reg(WRITE_REG1 + RX_PW_P4, TX_PLOAD_WIDTH); // 接收数据通道4有效数据 宽度32 范围1-32 SPI_RW_Reg(WRITE_REG1 + RX_PW_P5, TX_PLOAD_WIDTH); // 接收数据通道5有效数据 宽度32 范围1-32 SPI_RW_Reg(WRITE_REG1 + EN_AA, 0x3f); // 使能通道0-通道5接收自动应答 SPI_RW_Reg(WRITE_REG1 + EN_RXADDR, 0x3f); // 接收通道0-5 使能 SPI_RW_Reg(WRITE_REG1 + RF_CH, 0); // 选择射频工作频道0 范围0-127 if(nrf_baud==0) SPI_RW_Reg(WRITE_REG1 + RF_SETUP, 0x0f); // 0db, 2M BPS 射 频寄存器 无线速率bit5:bit3 发射功率bit2-bit1 37 // 00: 1M BPS 00:-18dB // 01: 2M BPS 01:-12dB // 10: 250K BPS 10:-6dB // 11:保留 11:0dB else if(nrf_baud==1) SPI_RW_Reg(WRITE_REG1 + RF_SETUP, 0x07); // 0db, 1M BPS else SPI_RW_Reg(WRITE_REG1 + RF_SETUP, 0x27); // 0db, 250K BPS SPI_RW_Reg(WRITE_REG1 + CONFIG, 0x0f); // bit6 接收中断产生时,IRQ引脚产 生低电平 // bit5 发送中断产生时,IRQ引脚产 生低电平 // bit4 最大重复发送次数完成时 IRQ引脚 产生低电平 // bit3 CRC校验允许 // bit2 16位CRC // bit1 上电 // bit0 接收模式 MODE_CE(1); // 使能接收模式 } /**************************************************************************** * 名 称:TX_Mode(void) * 功 能:设置NRF24L01+的发送模式 * 入口参数:无 * 出口参数:无 * 说 明:设置了6个发射通道地址、射频频道0、16位CRC、收发中断、增益0dB等等 * 调用方法:TX_Mode(); ****************************************************************************/ void TX_Mode(void) { MODE_CE(0); SPI_RW_Reg(WRITE_REG1 + SETUP_RETR, 0x1a); // 自动重发延时500us + 86us, 自动 重发计数10次 if(nrf_Pipe==0) SPI_Write_Buf(WRITE_REG1 + TX_ADDR, TX_ADDRESS0, TX_ADR_WIDTH); //数据通道0发送地址,最大5个字节 else if(nrf_Pipe==1) SPI_Write_Buf(WRITE_REG1 + TX_ADDR, TX_ADDRESS1, TX_ADR_WIDTH); //数据通道1发送地址,最大5个字节 else if(nrf_Pipe==2) SPI_Write_Buf(WRITE_REG1 + TX_ADDR, TX_ADDRESS2, TX_ADR_WIDTH); //数据通道2发送地址,最大5个字节 else if(nrf_Pipe==3) SPI_Write_Buf(WRITE_REG1 + TX_ADDR, TX_ADDRESS3, TX_ADR_WIDTH); //数据通道3发送地址,最大5个字节 38 else if(nrf_Pipe==4) SPI_Write_Buf(WRITE_REG1 + TX_ADDR, TX_ADDRESS4, TX_ADR_WIDTH); //数据通道4发送地址,最大5个字节 else if(nrf_Pipe==5) SPI_Write_Buf(WRITE_REG1 + TX_ADDR, TX_ADDRESS5, TX_ADR_WIDTH); //数据通道5发送地址,最大5个字节 if(nrf_Pipe==0) SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS0, TX_ADR_WIDTH); // 将0通道的接收地址设置为 0通道的发射地址 else if(nrf_Pipe==1) SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS1, TX_ADR_WIDTH); // 将0通道的接收地址设置为 1通道的发射地址 else if(nrf_Pipe==2) SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS2, TX_ADR_WIDTH); // 将0通道的接收地址设置为 2通道的发射地址 else if(nrf_Pipe==3) SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS3, TX_ADR_WIDTH); // 将0通道的接收地址设置为 3通道的发射地址 else if(nrf_Pipe==4) SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS4, TX_ADR_WIDTH); // 将0通道的接收地址设置为 4通道的发射地址 else if(nrf_Pipe==5) SPI_Write_Buf(WRITE_REG1 + RX_ADDR_P0, TX_ADDRESS5, TX_ADR_WIDTH); // 将0通道的接收地址设置为 5通道的发射地址 SPI_RW_Reg(WRITE_REG1 + CONFIG, 0x0e); // bit6 接收中断产生时,IRQ引脚产 生低电平 // bit5 发送中断产生时,IRQ引脚产 生低电平 // bit4 最大重复发送次数完成时 IRQ引脚 产生低电平 // bit3 CRC校验允许 // bit2 16位CRC // bit1 上电 // bit0 发送模式 MODE_CE(1); // 使能发送模式 } /**************************************************************************** * 名 称:delay_ms(unsigned int x) * 功 能:延时基数为1毫秒程序 * 入口参数:x 延时的毫秒数 * 出口参数:无 * 说 明:无 * 调用方法:delay_ms(1); ****************************************************************************/ void delay_ms(unsigned int x) { unsigned int i,j; i=0; for(i=0;i { j=108; while(j--); 39 } } /**************************************************************************** * 名 称:USB_To_NRF_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes) * 功 能:将保存在USB接收缓存区的32字节的数据通过NRF24L01+发送出去 * 入口参数:data_buffer USB接收缓存区 Nb_bytes USB缓存接收到的字节数 * 出口参数:无 * 说 明:当接收到的USB虚拟串口数据小于32,把有效数据外的空间用0填满 * 调用方法:RX_Mode(); ****************************************************************************/ void NRF24L01_TXBUF(uint8_t* data_buffer, uint8_t Nb_bytes) { unsigned char i = 0; MODE_CE(0); //NRF 模式控制 SPI_RW_Reg(WRITE_REG1+STATUS,0xff); //设置状态寄存器初始化 SPI_RW_Reg(FLUSH_TX,0); //清除TX FIFO寄存器 SPI_RW_Reg(FLUSH_RX,0); //清除RX FIFO寄存器 TX_Mode(); //设置为发送模式 delay_ms(10); if(Nb_bytes<32) { //当发送的数据长度小于32,把有效数据外的空间用0填满 for(i=Nb_bytes; i<32; i++) data_buffer[i] = 0; } SPI_Write_Buf(WR_TX_PLOAD, data_buffer, TX_PLOAD_WIDTH); //发送32字节 的缓存区数据到NRF24L01 MODE_CE(1); //保持10us以上,将数据发送出去 } 3.4.5 功能测试 测试数据 发送消息 接收消息 发送编码 123 HELLO 接受编码 123 HELLO 发送板直接输入123后,然后点击SEND后如图 3.18: 接收板接收到后如图3.19: 40 图3.18 图3.19 3.4.6 系统评价(结果分析) 基于Cortex-M3内核的奋斗STM32开发板,无线射频收发器nRF24L01P工作于2.4GM频 段,STM32和nRF24L01P之间采用SPI接口方式。 用STM32开发板和nRF24L01扩展板设计一个基于uC/OS-II的无线通信系统,并基于 UCGUI实现良好的人机界面,能够实现两个无线节点间的数据收发,实现俩个开发板互相收 发数据,可以输入自定义的数据,然后发送并对方接收,并能够将接收到的数据显示在液晶 屏上,可以清空显示屏接收的数据。可以用小键盘手动输入数据,实现大小写英文字母的转 换(shift键),实现良好的人机界面。双方可以互发数据,实现良好的通讯。 41 3.5.结论(体会) 通过这次课程设计,我学会了如何用STM32开发板和nRF24L01扩展板设计一个基于 uC/OS-II的无线通信系统,最后终于完成了课程设计的基本要求。在3到10周的实践与探 索中,我们遇到了一些问题,我们就请教老师和其他同学,将这些困难一一解决了,小组中的 每个成员都很团结,努力的配合组长所分配的任务,并且积极完成任务。在此次的课程设计 中,我们不仅巩固了之前学过的专业知识,也增强了动手能力,也明白了团队凝聚力也是很 重要的。 3.6.参考文献 1. 邵贝贝译,嵌入式实时操作系统 µC/OS-II(第二版)[M]. 北京:北京航空航天大学出版社, 2003. 2. 魏洪兴等,嵌入式系统设计师教程 [M].北京:清华大学出版社,2006. 3. 王田苗,魏洪兴,嵌入式系统设计与实例开发(第三版[M].北京:清华大学出版社,2008. 4. 李宁,基于MDK的STM32处理器开发应用北京:北京航空航天大学出版社,2008. 5. 刘波文,ARM Cortex-M3应用开发实例详解 [M].北京:电子工业出版社,2011. 6. 刘波文,黎胜容,ARM嵌入式项目开发三位一体实战精讲[M]. 北京:北京航空航天大学出版社,2011. 7. ST 0008 Reference Manual. 2011. 8. STMicroelectronics. STM32F10X参考手册. 9. STMicroelectronics. STM32固件库手册. 10. a-Si TFT LCD Single Chip Driver ——ILI9341数据手册 山东建筑大学计算机科学与技术学院 42 课程设计指导教师评语 班级: 学生姓名: 学号: 指导教师评语(包括工作态度,遵守纪律;基本理论、知识、技能;独立工作能 力和分析解决问题的能力;完成任务情况及水平): 学生成绩(百分制): 指导教师签名: 年 43 月 日


发布评论