您的位置 首页 传感器

STM32 驱动无线NRF24L01 完结串口数据传输

2401一个简单的SPI接口的2.4G射频模块淘宝价20¥,DIY的17¥,算是廉价。这个版本的稳定修正http://ntn314.blog.163.com/blo…

2401 一个简略的SPI 接口的 2.4G 射频模块 淘宝价20¥,DIY 的17¥ ,算是廉价。

这个版别的安稳批改http://ntn314.blog.163.com/blog/static/16174358420106211118944/
接口CMOS电平3.3V STM32 可直接衔接。承受完结 发送完结 犯错 都有IRQ 低电平中止产生。程序中 我将其衔接至一IO口在外部中止中处里各类事情 但也发现这种处理方式并不是特别灵敏,或许直接判别愈加灵敏。
NRF20L01一次能够传输 1~32个字节比较灵敏。开端我是依据字符串长来不断的转化每次传输的长度,这样做非常费事最后用截取有用串长的办法完结作用很好。
程序修修改正 总算安稳了 不过在传输大于32个字节的信息时犯错的概率很大,原因暂时不清楚,不过能主动康复过来。另外在带有硬件的在线仿真调试的时分一定要运行前断开外部硬件的电源再从头衔接,确保外部器材的正常初始化。
/***********************s****************************/
u8 tran=0; //中止标志
u8 sta; //界说一个可位寻址的变量sta
uc8 TX_ADDRESS[TX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
char RX_BUF[256];
uchar TX_BUF[256];
/**************************************************/
void RF_SPI_Config(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);

/* PB15-MOSI2,PB13-SCK2*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 |GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

//IRQ
GPIO_SetBits(GPIOB, GPIO_Pin_0);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
/* 装备中止线0为下降触发*/
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/*PB2-CS*/
GPIO_SetBits(GPIOB, GPIO_Pin_2);//预置为高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*PC4-A0*/
GPIO_SetBits(GPIOC, GPIO_Pin_4);//预置为高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/*LED*/
GPIO_SetBits(GPIOB, GPIO_Pin_12);//预置为高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI2 configuration */
SPI_Cmd(SPI2, DISABLE); //必须先禁能,才干改动MODE
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//两线全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//CPOL=0 时钟悬空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//CPHA=0 数据捕获第1个
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64 ;//64分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC7

SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);

}
/**************************************************************
但牢记不行疏忽SPI的硬件接纳,由于读SPI_DR才干铲除RXEN
***************************************************************/
u8 SPI_RW(u8 byte)
{
/*等候发送寄存器空*/
while((SPI2->SR & SPI_I2S_FLAG_TXE)==RESET);
/*发送一个字节*/
SPI2->DR = byte;
/* 等候接纳寄存器有用*/
while((SPI2->SR & SPI_I2S_FLAG_RXNE)==RESET);
return(SPI2->DR);
}
/**************************************************
函数:SPI_RW_Reg()
描绘:写数据value到reg寄存器
*************************************************/
u8 SPI_RW_Reg(u8 reg, u8 value)
{
u8 status;
CSN_L; // CSN置低,开端传输数据
status = SPI_RW(reg); // 挑选寄存器,一起回来状况字
SPI_RW(value); // 然后写数据到该寄存器
CSN_H; // CSN拉高,完毕数据传输
return(status); // 回来状况寄存器
}
/**************************************************
函数: init_io()
描绘:初始化IO
*************************************************/
void RX_Mode(void);
void init_io(void)
{
CE_L; // 待机
CSN_H; // SPI制止
LED1;// 封闭指示灯
RX_Mode();//接纳
}
/**************************************************
函数:SPI_Read()
描绘:从reg寄存器读一字节
*************************************************/
u8 SPI_Read(u8 reg)
{
u8 reg_val;
CSN_L; // CSN置低,开端传输数据
SPI_RW(reg); // 挑选寄存器
reg_val = SPI_RW(0); // 然后从该寄存器读数据
CSN_H; // CSN拉高,完毕数据传输
return(reg_val); // 回来寄存器数据
}
/**************************************************
函数:SPI_Read_Buf()
描绘:从reg寄存器读出bytes个字节,一般用来读取接纳通道
数据或接纳/发送地址
*************************************************/
uchar SPI_Read_Buf(uchar reg, char * pBuf, uchar bytes)
{
uchar status, i;
CSN_L; // CSN置低,开端传输数据
status = SPI_RW(reg); // 挑选寄存器,一起回来状况字
for(i=0; i pBuf[i] = SPI_RW(0); // 逐一字节从nRF24L01读出
CSN_H; // CSN拉高,完毕数据传输
return(status); // 回来状况寄存器
}
/**************************************************
函数:SPI_Write_Buf()
描绘:把pBuf缓存中的数据写入到nRF24L01,一般用来写入发
射通道数据或接纳/发送地址
*************************************************/
uchar SPI_Write_Buf(uchar reg, uchar * pBuf, uchar bytes)
{
uchar status, i;
CSN_L; // CSN置低,开端传输数据
status = SPI_RW(reg); // 挑选寄存器,一起回来状况字
for(i=0; i SPI_RW(pBuf[i]); // 逐一字节写入nRF24L01
CSN_H; // CSN拉高,完毕数据传输
return(status); // 回来状况寄存器
}
/**************************************************
函数:RX_Mode()
描绘:这个函数设置nRF24L01为接纳形式,等候接纳发送设备的数据包
*************************************************/
void RX_Mode(void)
{
CE_L;
SPI_Write_Buf(RF_WRITE_REG + RX_ADDR_P0, (u8*)TX_ADDRESS, TX_ADR_WIDTH); // 接纳设备接纳通道0运用和发送设备相同的发送地址
SPI_RW_Reg(RF_WRITE_REG + EN_AA, 0x01); // 使能接纳通道0主动应对
SPI_RW_Reg(RF_WRITE_REG + EN_RXADDR, 0x01); // 使能接纳通道0
SPI_RW_Reg(RF_WRITE_REG + RF_CH, 40); // 挑选射频通道0x40
SPI_RW_Reg(RF_WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // 接纳通道0挑选和发送通道相同有用数据宽度
SPI_RW_Reg(RF_WRITE_REG + RF_SETUP, 0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益
SPI_RW_Reg(RF_WRITE_REG + CONFIG, 0x0f); // CRC使能,16位CRC校验,上电,接纳形式
CE_H; // 拉高CE发动接纳设备
}
/**************************************************
函数:TX_Mode()
描绘:
这个函数设置nRF24L01为发送形式,(CE=1继续至少10us),
130us后发动发射,数据发送完毕后,发送模块主动转入接纳
形式等候应对信号。
*************************************************/
void TX_Mode(uchar * BUF)
{
CE_L;
SPI_Write_Buf(RF_WRITE_REG + TX_ADDR, (u8*)TX_ADDRESS, TX_ADR_WIDTH); // 写入发送地址
SPI_Write_Buf(RF_WRITE_REG + RX_ADDR_P0, (u8*)TX_ADDRESS, TX_ADR_WIDTH); // 为了应对接纳设备,接纳通道0地址和发送地址相同
SPI_Write_Buf(WR_TX_PLOAD, BUF, TX_PLOAD_WIDTH); // 写数据包到TX FIFO
SPI_RW_Reg(RF_WRITE_REG + EN_AA, 0x01); // 使能接纳通道0主动应对
SPI_RW_Reg(RF_WRITE_REG + EN_RXADDR, 0x01); // 使能接纳通道0
SPI_RW_Reg(RF_WRITE_REG + SETUP_RETR, 0x0a); // 主动重发延时等候250us+86us,主动重发10次
SPI_RW_Reg(RF_WRITE_REG + RF_CH, 40); // 挑选射频通道0x40
SPI_RW_Reg(RF_WRITE_REG + RF_SETUP, 0x07); // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益
SPI_RW_Reg(RF_WRITE_REG + CONFIG, 0x0e); // CRC使能,16位CRC校验,上电
CE_H;CE_H;delay_ms(1);
}
/**************************************************
函数:Check_ACK()
描绘:
查看接纳设备有无接纳到数据包,设定没有收到应对信
号是否重发
***************************************************/
uchar Check_ACK(u8 clear)
{
while(IRQ);
sta = SPI_RW(NOP); // 回来状况寄存器
if(MAX_RT)
if(clear) // 是否铲除TX FIFO,若没有铲除在铲除MAX_RT中止标志后重发
SPI_RW(FLUSH_TX);
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 铲除TX_DS或MAX_RT中止标志
IRQ_H;
if(TX_DS)
return(0x00);
else
return(0xff);
}
void sent_data(u8* fp,u16 flong)
{
u16 i=65535;
TX_Mode((u8*)&flong); //传送长度
while(!tran&&i>1)i–; //等候完结
tran=0;
flong=flong/33+1;
for(i=0;i<20000;i++);//130uS*2延时
while(flong)
{
if(MAX_RT) return;//无应对回来
TX_Mode(fp); //传送数据
while(!tran&&i>1)i–; //等候完结
tran=0;
for(i=0;i<20000;i++);//130uS*2延时
fp+=32;flong–;
}
}
extern u8 RX_NU;
void test (void)
{
if (Uart2_Get_Flag!=0&&Timer2==0)
{
sent_data(TX_BUF,(u16)Uart2_Get_Flag);
Uart2_Get_Flag=0;
}

if(Timer2==0&&RX_NU==2)
{
RX_NU=1;
USART2_Puts(“传输过错 “);
USART2_Puts(“\r\n”);
}
}

两个中止 串口 和 外部中止
/*******************************************************************************
* Function Name : EXTI0_IRQHandler
* Description : This function handles External interrupt Line 0 request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
extern u8 sta;
extern char RX_BUF[256];
extern uchar TX_BUF[256];
extern u8 SPI_RW_Reg(u8 reg, u8 value);
extern void RX_Mode(void);
extern uchar SPI_Read_Buf(uchar reg, char * pBuf, uchar bytes);
u8 RX_NU=1;//1接纳长度 2接纳数据
u16 rectnu,onerc; //接纳串长,接纳次数
char* PRX_BUF=RX_BUF;
void EXTI0_IRQHandler(void)
{
EXTI_ClearITPendingBit(EXTI_Line0);
tran=1;
CSN_L;
sta=SPI_RW(NOP); // 回来状况寄存器
CSN_H;

if(MAX_RT)
{
USART2_Puts(“对方无应对 “);
CSN_L;
SPI_RW(FLUSH_TX); // 铲除TX FIFO,若没有铲除在铲除MAX_RT中止标志后重发
CSN_H;
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta);
}

if(TX_DS)
{
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 铲除TX_DS或MAX_RT中止标志
}

if(RX_DR) // 判别是否承受到数据
{

if(RX_NU==1)
{
CE_L;
SPI_Read_Buf(RD_RX_PLOAD, RX_BUF, TX_PLOAD_WIDTH); // 从RX FIFO读出数据
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 铲除RX_DS中止标志
rectnu=RX_BUF[0];rectnu|=RX_BUF[1]<<8; //接纳串长
onerc=rectnu/33+1; //核算接纳次数
RX_NU=2;RX_Mode();Timer2=500;/*超时时刻*/
return;
}

if(RX_NU==2)
{
CE_L;
SPI_Read_Buf(RD_RX_PLOAD, PRX_BUF, TX_PLOAD_WIDTH); // 从RX FIFO读出数据
SPI_RW_Reg(RF_WRITE_REG + STATUS, sta); // 铲除RX_DS中止标志
onerc–;PRX_BUF+=32; //接纳计数 接纳指针移动
if(!onerc)
{
RX_BUF[rectnu]=\0; //截取有用串长
USART2_Puts(RX_BUF); //串口发送接纳到的字符
USART2_Puts(“\r\n”);
PRX_BUF=RX_BUF; //康复指针
RX_NU=1;
}
RX_Mode();Timer2=200;/*超时时刻*/
return;
}
}
LED;
RX_Mode();
}

/*******************************************************************************
* Function Name : USART2_IRQHandler
* Description : This function handles USART2 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
extern u16 Uart2_Get_Flag;
extern u8 Uart2_Get_Data;
extern u8 TX_BUF[256];
void USART2_IRQHandler(void)
{
//接纳中止
if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
{
Timer2=500;//500MS后nfr2401发送
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
TX_BUF[Uart2_Get_Flag]=USART_ReceiveData(USART2);
Uart2_Get_Flag++;
//USART2_Puts(TX_BUF);
}

//溢出-假如产生溢出需求先读SR,再读DR寄存器 则可铲除不断入中止的问题
if(USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET)
{
USART_ClearFlag(USART2,USART_FLAG_ORE);//读SR
USART_ReceiveData(USART2);//读DR
}
}

在 外部中止中 能够一次传输最少要两次 第一次RX_NU==1 用来接纳此次传输的数据长度 用来截取有用串长,第2次RX_NU==2 就收数据放到数组里 若是数据善于32个字节就分屡次传输。其间引进 超时机制 若是200/500 MS 后传输还没完结(RX_NU再次 等于1)就抛弃接纳数据 直接接纳再次新的串长度。这个机制很重要但还有待完善。

串口中也相同500MS 还没新的数据进来就阐明串口接纳完结 之后就发送数据。Uart2_Get_Flag 当然便是串长了。

NRF24L01 能够参阅其数据手册 都是中文好说好说~~这儿就不提了。

#ifndef _API_DEF_
#define _API_DEF_

// Define interface to nRF24L01

//* Define SPI pins
/*sbit CE = P1^0; // Chip Enable pin signal (output)
sbit CSN = P1^1; // Slave Select pin, (output to CSN, nRF24L01)
sbit IRQ = P1^3; // Interrupt signal, from nRF24L01 (input)
sbit MISO = P1^4; // Master In, Slave Out pin (input)
sbit MOSI = P1^5; // Serial Clock pin, (output)
sbit SCK = P1^7; // Master Out, Slave In pin (output)
*/

// SPI(nRF24L01) commands
#define RF_READ_REG 0x00 // Define read command to register
#define RF_WRITE_REG 0x20 // Define write command to register
#define RD_RX_PLOAD 0x61 // Define RX payload register address
#define WR_TX_PLOAD 0xA0 // Define TX payload register address
#define FLUSH_TX 0xE1 // Define flush TX register command
#define FLUSH_RX 0xE2 // Define flush RX register command
#define REUSE_TX_PL 0xE3 // Define reuse TX payload register command
#define NOP 0xFF // Define No Operation, might be used to read status register

// SPI(nRF24L01) registers(addresses)
#define CONFIG 0x00 // Config register address
#define EN_AA 0x01 // Enable Auto Acknowledgment register address
#define EN_RXADDR 0x02 // Enabled RX addresses register address
#define SETUP_AW 0x03 // Setup address width register address
#define SETUP_RETR 0x04 // Setup Auto. Retrans register address
#define RF_CH 0x05 // RF channel register address
#define RF_SETUP 0x06 // RF setup register address
#define STATUS 0x07 // Status register address
#define OBSERVE_TX 0x08 // Observe TX register address
#define CD 0x09 // Carrier Detect register address
#define RX_ADDR_P0 0x0A // RX address pipe0 register address
#define RX_ADDR_P1 0x0B // RX address pipe1 register address
#define RX_ADDR_P2 0x0C // RX address pipe2 register address
#define RX_ADDR_P3 0x0D // RX address pipe3 register address
#define RX_ADDR_P4 0x0E // RX address pipe4 register address
#define RX_ADDR_P5 0x0F // RX address pipe5 register address
#define TX_ADDR 0x10 // TX address register address
#define RX_PW_P0 0x11 // RX payload width, pipe0 register address
#define RX_PW_P1 0x12 // RX payload width, pipe1 register address
#define RX_PW_P2 0x13 // RX payload width, pipe2 register address
#define RX_PW_P3 0x14 // RX payload width, pipe3 register address
#define RX_PW_P4 0x15 // RX payload width, pipe4 register address
#define RX_PW_P5 0x16 // RX payload width, pipe5 register address
#define FIFO_STATUS 0x17 // FIFO Status Register register address

#endif /* _API_DEF_ */

#ifndef HAL_H
#define HAL_H
//硬件初始化
extern void ChipHalInit(void);
extern void ChipOutHalInit(void);
extern void delay_ms(u16 dly_ms);
extern void USART_Configuration(void);
extern void RF_SPI_Config(void);
extern volatile u16 Timer1,Timer2;
//RF_2401
extern void init_io(void);
extern void test (void);
extern u8 tran;//中止进入标志
extern u8 SPI_Read(u8 reg);
extern u8 SPI_RW(u8 byte);
#define TX_ADR_WIDTH 5 // 5字节宽度的发送/接纳地址
#define TX_PLOAD_WIDTH 32 // 接纳字节数32个字
#define uchar u8
/*操控引脚*/
#define CE_HGPIOC->BSRR=GPIO_Pin_4
#define CE_LGPIOC->BRR=GPIO_Pin_4

#define CSN_HGPIOB->BSRR=GPIO_Pin_2
#define CSN_LGPIOB->BRR=GPIO_Pin_2

#define IRQ(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0))
#define IRQ_HGPIOB->BSRR=GPIO_Pin_0

#define LED1GPIOB->BSRR=GPIO_Pin_12
#define LED0GPIOB->BRR=GPIO_Pin_12
#define LED GPIOB->ODR=((GPIOD->ODR)^GPIO_Pin_12)

#define RX_DR ((sta>>6)&0X01)
#define TX_DS ((sta>>5)&0X01)
#define MAX_RT ((sta>>4)&0X01)

//USART
extern void USART2_Putc(unsigned char c);
extern void USART2_Puts(char * str);
extern u16 Uart2_Get_Flag;//串口2接纳到数据长度
extern u8 Uart2_Get_Data;//串口2接纳的数据
#endif

中止用前留意优先级的设置

#include “STM32Lib\\stm32f10x.h”
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

/* 装备中止运用组合1*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

/* EXTI0*/
NVIC_InitStructure.NVIC_IRQChannel =EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

/*UART2*/
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NV%&&&&&%_InitStructure);

}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/252342.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部