因为最近在弄比赛,做了个六足蜘蛛用到了nrf24l01无线通信模块,故作此笔记以便记录,一来分享自己的经验,二来也方便自己未来的学习回顾。本文章不过多讲述原理,主要讲解怎么使用!
首先 我用的nrf24l01模块是配套使用的,如下图。此模块利用串口通信进行发收消息,注意单片机端的接口与nrf24l01接口的接法,单片机的Tx应接nrf24l01模块的Rx,单片机的Rx接nrf24l01模块的Tx。
因为蜘蛛USART1是用来控制总线串行舵机,所以我利用USART3来实现这个模块的通信。stm32上串口3的接口为PB11,PB10,如下图
接下来便是代码:
uart3.h
#ifndef __USART3_H #define __USART3_H #include "stdio.h" #include "sys.h" #define USART_REC_LEN 200 //定义最大接收字节数 200 #define EN_USART3_RX 1 //使能(1)/禁止(0)串口3接收 //extern u8 Res; extern u8 USART3_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern u16 USART3_RX_STA; //接收状态标记 //如果想串口中断接收,请不要注释以下宏定义 void uart3_init(u32 bound); //void MY_USART3_Init(void); #endif
uart3.c
注意,如果程序中还有串口1 uart.c的配置,那么uart3.c将会与之冲突,在此我们只要将uart.c中的
/int fputc(int ch, FILE *f)
//{
// if(ch =='n')
// {
// USART_SendData(USART1, 0x0D);
// while (!(USART1->SR & USART_FLAG_TXE));
// USART_SendData(USART1, 0x0A);
// while (!(USART1->SR & USART_FLAG_TXE));
// }
// else
// {
// USART_SendData(USART1, (unsigned char)ch);
// while (!(USART1->SR & USART_FLAG_TXE));
// }
// return ch;
//}
注释掉,不然会与UART3.c中的冲突,重复定义
此程序为uart3.c的配置
#include "sys.h"
#include "uart3.h"
//
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS //0
#include "includes.h" //ucos 使用
#endif
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART3->SR&0x40)==0);//循环发送,直到发送完毕
USART3->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART3_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART3_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART3_RX_STA=0; //接收状态标记
//u8 Res;
void uart3_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3,
//USART3_TX GPIOB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.10
//USART1_RX GPIOB.11初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.11
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART3, &USART_InitStructure); //初始化串口3
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断(USART_IT_RXNE
USART_Cmd(USART3, ENABLE); //使能串口3
}
void USART3_IRQHandler(void) //串口3中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART3); //读取接收到的数据
if((USART3_RX_STA&0x8000)==0)//接收未完成
{
if(USART3_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART3_RX_STA=0;//接收错误,重新开始
else USART3_RX_STA|=0x8000; //接收完成了
}
else //还没收到0x0D
{
if(Res==0x0d)USART3_RX_STA|=0x4000;
else
{
USART3_RX_BUF[USART3_RX_STA&0x3FFF]=Res ;
USART3_RX_STA++;
if(USART3_RX_STA>(USART_REC_LEN-1))USART3_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
#endif
main.c
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "beep.h"
#include "uart.h"
#include "LobotSerialServo.h"
#include "bool.h"
#include "uart3.h"
#define ID1 1
#define ID2 2
int main(void)
{
u16 t; //警告,变量被声明但未被引用
u16 len;
u16 times=0;
vu8 key=0;
uart3_init(115200); //串口初始化为115200
SystemInit(); //系统时钟等初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先
uartInit(115200);//串口初始化为115200
delay_init(); //延时函数初始化
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
BEEP_Init(); //初始化蜂鸣器端口
while(1)
{
if(USART3_RX_STA&0x8000)
{
len=USART3_RX_STA&0x3fff;//得到此次接收到的数据长度
for(t=0;t
在主函数中USART3_RX_BUF[t]用于储存电脑发送的字符(识别的是ASCLL码),我们可以通过判断USART3_RX_BUF[t]是否等于自己发送的字符对应的ascll码就可以执行自己想要执行的程序了,比如我上面是if(USART3_RX_BUF[t]==0x39)(9对应的ASCLL码的十六进制),如果电脑发送的是字符9,那么LED1翻转,串口舵机1转动到200位置。
其他常用字符对应的ASCLL码
还有更多字符对应的ASCLL码大家可以自行搜索。 电脑发送的上位机一般淘宝卖家都会有,正点原子XCOM软件用于串口通信的。软件方面发送的配置要跟自己UART3.c中配置的一样才能正常发送(比如停止位,波特率)
这个蜘蛛还涉及IIC控制16路pwm/servo发生器控制板 ,串口总线舵机,以及六足蜘蛛步态解析,之后会一一记录。



