硬件平台 :友善之臂Ting4412
: NRF24L01 2.4G无线模块SPI接口
内核版本:Linux3.5
硬件连接方式
以前在STM32F103C8T6上使用STM32的SPI控制器驱动过NRF24L01 2.4G无线模块,最近学习Linux设备驱动,刚好同学手边有一个Tiny4412开发板就当是练练手,顺便学习学习Linux下SPI设备驱动的编写。
NRF24L01 2.4G无线模块的SPI驱动暂时只是调试通过,能够实现Tiny4412通过NRF24L01 2.4G无线模块发送数据,暂时没写成字符设备驱动,在内核定时器中调用spi_write函数不断发送数据。
通信现象:
STM32没接到数据就会报错,如下:
一旦加载驱动模块,就立马接收正常,如下:
......................................................................................只说流程,不说原理............................................................................
1、构造struct spi_board_info对象,这里我们暂时构造两个,方便以后在SPI0控制器上挂载两个NFR24L01设备,实现相互收发数据。
struct s3c64xx_spi_csinfo cs0={
.fb_delay = 0,
.line = EXYNOS4_GPX3(2),//片选引脚
};
struct s3c64xx_spi_csinfo cs1={
.fb_delay = 0,
.line = EXYNOS4_GPX3(4),//片选引脚
};
static struct spi_board_info nrf24l01_spi_info[]={
{
.modalias = DEV_NAME_01,
.max_speed_hz = 10*1000*1000,//最大时钟,需比设备要求的时钟大,暂选10Mhz
.bus_num = 0,/*exynos4412 的spi0控制器*/
.chip_select = EXYNOS4_GPX3(2),/*由spi master确定其最大值*/
.mode = SPI_MODE_0,
.platform_data = (void*)EXYNOS4_GPX3(3), /*平台数据,作为NRF24LXX的CE引脚*/
.controller_data= (void*)&cs0,
},
{
.modalias = DEV_NAME_02,
.max_speed_hz = 10*1000*1000,//最大时钟,需比设备要求的时钟大,暂选10Mhz
.bus_num = 0,/*exynos4412 的spi0控制器*/
.chip_select = EXYNOS4_GPX3(4),/*由spi master确定其最大值*/
.mode = SPI_MODE_0,
.platform_data = (void*)EXYNOS4_GPX3(5), /*平台数据,作为NRF24LXX的CE引脚*/
.controller_data= (void*)&cs1,
},
};
2、注册它,内核会依据构造的struct spi_board_info 对象创建对应的struct spi_device对象。
在init函数中注册构造好的truct spi_board_info对象static struct spi_board_info nrf24l01_spi_info[]
static int __init demo_init(void)
{
printk(KERN_INFO"current func is-------------------------------------------%s\n",__FUNCTION__);
/*spi_register_board_info
*依照spi_board_info 和spi_master的bus_num比较,匹配成功会生成一个对应的spi_device对象
*/
return spi_register_board_info(nrf24l01_spi_info,ARRAY_SIZE(nrf24l01_spi_info));
}
看看spi_register_board_info干了什么?
int spi_register_board_info(struct spi_board_info const *info, unsigned n)
//master和bi->board_info的bus_nus比较,相等则调用spi_new_device创建spi_device对象
spi_match_master_to_boardinfo(master, &bi->board_info);调用spi_new_device
spi_new_device(struct spi_master *master,struct spi_board_info *chip)
int spi_add_device(struct spi_device *spi)//注册struct spi_device
/*spi_add_device注册struct spi_device时候会做一些判断,一会进去分析 */
分析spi_new_device
int spi_register_board_info(struct spi_board_info const *info, unsigned n)
//master和bi->board_info的bus_nus比较,相等则调用spi_new_device创建spi_device对象
spi_match_master_to_boardinfo(master, &bi->board_info);调用spi_new_device
spi_new_device(struct spi_master *master,struct spi_board_info *chip)
int spi_add_device(struct spi_device *spi)//注册struct spi_device
/*spi_add_device注册struct spi_device时候会做一些判断,比如我们第一步构造
*static struct spi_board_info中的chip_select会和spi_master的num_chipselect做比较
*要求设置我们的片选信号不能大于spi_master的num_chipselect
* if (spi->chip_select >= spi->master->num_chipselect) {
* dev_err(dev, "cs%d >= max %d\n",spi->chip_select,spi->master->num_chipselect);
* return -EINVAL;//直接报错返回,导致我们不能注册spi_device对象......
* 这个问题怎么解决?我们直接修改spi主控器驱动就好了。
*}
* 修改 vi arch/arm/mach-exynos/mach-tiny4412.c中设置spi控制器函数
* s3c64xx_spi0_set_platdata(NULL,0,1)这个函数就好了,内核默认设置
* 最大片选值为1,也就是说默认最多支持1个spi设备,那好了我们把它修改
* 大一些就好了,直接修改到0xffff,保证它一定能注册成功。
*/
struct s3c64xx_spi_csinfo cs0={
.fb_delay = 0,
.line = EXYNOS4_GPX3(2),
};
struct s3c64xx_spi_csinfo cs1={
.fb_delay = 0,
.line = EXYNOS4_GPX3(4),
};
好了下面编译成模块,但是编译的时候报WARNING: "spi_register_board_info"/nrf24xx_spi_device.ko] undefined!第一感觉是
spi_register_board_info相关的头文件没有,但是相关spi的头文件都加了,查资料发现原来是linux3.5源码中没有将spi_register_board_info函数导出符号表。那好,就编译进内核得了,将nrf24xx_spi_device.c复制drivers/spi目录下,修改Makefile,将nrf24xx_spi_device.c编译进内核。下面先给出nrf24xx_spi_device.c源码。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/******************硬件相关的信息****************/
#define DEV_NAME_01 "nrf24xx_spi_01"
#define DEV_NAME_02 "nrf24xx_spi_02"
#define DEV1_CS_PIN EXYNOS4_GPX3(2)
#define DEV2_CS_PIN EXYNOS4_GPX3(4)
#define DEV1_CE_PIN EXYNOS4_GPX3(3)
#define DEV2_CE_PIN EXYNOS4_GPX3(5)
/*
片选引脚接在GPX3_2
*/
struct s3c64xx_spi_csinfo cs0={
.fb_delay = 0,
.line = EXYNOS4_GPX3(2),//片选引脚
};
struct s3c64xx_spi_csinfo cs1={
.fb_delay = 0,
.line = EXYNOS4_GPX3(4),//片选引脚
};
static struct spi_board_info nrf24l01_spi_info[]={
{
.modalias = DEV_NAME_01,
.max_speed_hz = 2*1000*1000,//最大时钟,需比设备要求的时钟大,暂选2Mhz
.bus_num = 0,/*exynos4412 的spi0控制器*/
.chip_select = EXYNOS4_GPX3(2),/*由spi master确定其最大值*/
.mode = SPI_MODE_0,
.platform_data = (void*)EXYNOS4_GPX3(3), /*平台数据,作为NRF24LXX的CE引脚*/
.controller_data= (void*)&cs0,
},
{
.modalias = DEV_NAME_02,
.max_speed_hz = 2*1000*1000,//最大时钟,需比设备要求的时钟大,暂选2Mhz
.bus_num = 0,/*exynos4412 的spi0控制器*/
.chip_select = EXYNOS4_GPX3(4),/*由spi master确定其最大值*/
.mode = SPI_MODE_0,
.platform_data = (void*)EXYNOS4_GPX3(5), /*平台数据,作为NRF24LXX的CE引脚*/
.controller_data= (void*)&cs1,
},
};
static int __init demo_init(void)
{
printk(KERN_INFO"current func is-------------------------------------------%s\n",__FUNCTION__);
/*spi_register_board_info
*依照spi_board_info 和spi_master的bus_num比较,匹配成功会生成一个对应的spi_device对象
*/
return spi_register_board_info(nrf24l01_spi_info,ARRAY_SIZE(nrf24l01_spi_info));
}
static void __exit demo_exit(void)
{
printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
make zImage,启动内核。在sys/bus/spi/devices目录下出现下面spi0.220 spi0.222两个节点,如图:
其中0表示bus_num,220和222表示我们的static struct spi_board_info nrf24l01_spi_info[0]的.chip_select = EXYNOS4_GPX3(2),//这个宏的值就是220同理222就是EXYNOS4_GPX3(4),默认内核只创建spi0.0、spi2.0。注意现在只是在内核中创建了spi_device,还没nrf24xx的驱动。nrf24xx_spi_driver就是在STM32程序基础上简单的修修改改就好了,对比Tiny4412和STM32的程序你会发现关于nrf24l01的代码名字是一样的。
..............................................................下面就直接给出nrf24xx_spi_driver.c的源码.........................................................................
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "nrf24xx.h"
#define DEVICE_NUM 1
#define GPX3CON 0x11000C60
#define GPX3DAT 0x11000C64
#define DEV_NAME_01 "nrf24xx_spi_01"
#define DEV_NAME_02 "nrf24xx_spi_02"
#define DEV_NAME DEV_NAME_01
#define DEV1_CS_PIN EXYNOS4_GPX3(2)
#define DEV2_CS_PIN EXYNOS4_GPX3(4)
#define DEV1_CE_PIN EXYNOS4_GPX3(3)
#define DEV2_CE_PIN EXYNOS4_GPX3(5)
unsigned char TX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01}; //发送地址
unsigned char RX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01};
static struct work_struct work;
struct timer_list timer;
struct spi_device *nrf24xx_spi;
static int nrf24l01_spi_probe(struct spi_device *spi);
static int nrf24l01_spi_remove(struct spi_device *spi);
void Nrf24L10_RX_Mode(void);
void Nrf24L10_TX_Mode(void);
unsigned char SPI1_ReadBuf(unsigned char reg,unsigned char *buf,unsigned char length);
unsigned char SPI1_SendBuf(unsigned char reg,unsigned char *buf,unsigned char length);
unsigned char SPI1_Write_Register(unsigned char reg,unsigned char data);
void Active_Nrf24l10(unsigned char cmd);
unsigned int SPI1_Read_Reg(unsigned char reg,unsigned char *status);
unsigned char Nrf24l10_SendBuf(unsigned char* data_buffer, unsigned char length);
unsigned char Nrf24l0_ReceiveBuf(unsigned char *buf);
unsigned char Nrf24l10_Irq(void);
char tmp=0,counter =0;
static struct spi_driver nrf24l01_spi_driver={
.driver={
.name = DEV_NAME,
.bus =&spi_bus_type,
.owner = THIS_MODULE,
},
.probe = nrf24l01_spi_probe,
.remove =__devexit_p(nrf24l01_spi_remove),
};
static void timer_function(unsigned long counter)
{
//printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
tmp = tmp?0:1;
gpio_set_value(DEV2_CE_PIN,tmp);
mod_timer(&timer,jiffies+HZ);
schedule_work(&work);
}
/*中断底半部中发送数据*/
static void irqBottom(struct work_struct *work)
{
char wbuf[50]={0};
int ret =0;
// char reg = EN_AA;
counter = counter>30? 0:counter;
sprintf(wbuf,"Message Comes From Linux -%d %c",counter,'\0');
counter++;
ret = Nrf24l10_SendBuf(wbuf,RX_PLOAD_WIDTH_32);//该函数会导致休眠,不能在中断函数中使用
printk("Message Send to STM3 .......%d\n",counter);
}
static int nrf24l01_spi_probe(struct spi_device *spi)
{
nrf24xx_spi = spi;
printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
printk(KERN_INFO"max_speed_hz:%d\n",spi->max_speed_hz);
printk(KERN_INFO"chip_select:%d\n",spi->chip_select);
INIT_WORK(&work, irqBottom);
s3c_gpio_cfgpin(DEV1_CS_PIN, S3C_GPIO_OUTPUT);//设置片选为输出
s3c_gpio_cfgpin(DEV2_CS_PIN, S3C_GPIO_OUTPUT);//设置片选为输出
s3c_gpio_cfgpin(DEV1_CE_PIN, S3C_GPIO_OUTPUT);//设置片选为输出
s3c_gpio_cfgpin(DEV2_CE_PIN, S3C_GPIO_INPUT);//设置片选为输出
Nrf24L10_TX_Mode();
init_timer(&timer);//初始化内核定时器
timer.function = timer_function;
add_timer(&timer);
return 0;
}
static int nrf24l01_spi_remove(struct spi_device *spi)
{
printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
del_timer(&timer);
return 0;
}
static int __init demo_init(void)
{
int err;
printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
err = spi_register_driver(&nrf24l01_spi_driver);
return err;
}
static void __exit demo_exit(void)
{
printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
spi_unregister_driver(&nrf24l01_spi_driver);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
void Nrf24L10_RX_Mode(void)
{
Active_Nrf24l10(0);//进入设置模式
SPI1_SendBuf(WRITE_REG1 + RX_ADDR_P0, RX_ADDRESS, TX_ADR_WIDTH_5); //数据通道0发送地址,最大5个字节
SPI1_Write_Register(WRITE_REG1 + EN_AA, 0x01); // 使能通道0-通道5接收自动应答
SPI1_Write_Register(WRITE_REG1 + EN_RXADDR, 0x01); //接收通道0-5 使能
SPI1_Write_Register(WRITE_REG1 + RF_CH, 40); // 选择射频工作频道0 范围0-127 频道选择寄存器
SPI1_Write_Register(WRITE_REG1+RX_PW_P0,RX_PLOAD_WIDTH_32);
SPI1_Write_Register(WRITE_REG1 + RF_SETUP, 0x0f);
SPI1_Write_Register(WRITE_REG1 + CONFIG, 0x0f);
Active_Nrf24l10(1);//激活发送
}
void Nrf24L10_TX_Mode(void)
{
Active_Nrf24l10(0);
SPI1_SendBuf(WRITE_REG1 + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH_5); //数据通道0发送地址,最大5个字节
SPI1_SendBuf(WRITE_REG1 + RX_ADDR_P0, RX_ADDRESS, TX_ADR_WIDTH_5);//数据通道0发送地址,最大5个字节
SPI1_Write_Register(WRITE_REG1 + EN_AA, 0x01);// 使能通道0-通道5接收自动应答
SPI1_Write_Register(WRITE_REG1 + EN_RXADDR, 0x01);//接收通道0-5 使能
SPI1_Write_Register(WRITE_REG1+SETUP_RETR,0x1a);
SPI1_Write_Register(WRITE_REG1 + RF_CH, 40);// 选择射频工作频道0 范围0-127 频道选择寄存器
SPI1_Write_Register(WRITE_REG1 + RF_SETUP, 0x0f);
SPI1_Write_Register(WRITE_REG1 + CONFIG, 0x0e);
Active_Nrf24l10(1); // 使能发送模式
}
unsigned int SPI1_Read_Reg(unsigned char reg,unsigned char *status)
{
unsigned char wbuf=reg;
struct spi_message m;
struct spi_transfer t[2] = {
{
.tx_buf = &wbuf,
.len = 1,
},
{
.rx_buf = status,
.len = 1,
},
};
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
return spi_sync(nrf24xx_spi, &m);
}
unsigned char SPI1_Write_Register(unsigned char reg,unsigned char data)
{
unsigned char wbuf[2]={0};
struct spi_message m;
struct spi_transfer t = {
.tx_buf = wbuf,
.len = 2,
};
//printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
wbuf[0]=reg;
wbuf[1]=data;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(nrf24xx_spi, &m);
}
/*
SPI1发送一个缓冲区
*/
unsigned char SPI1_SendBuf(unsigned char reg,unsigned char *buf,unsigned char length)
{
struct spi_message m;
unsigned char wbuf=reg;
struct spi_transfer t[2] = {
{
.tx_buf = &wbuf,
.len = 1,
},
{
.tx_buf = buf,
.len = length,
},
};
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
return spi_sync(nrf24xx_spi, &m);
}
unsigned char SPI1_ReadBuf(unsigned char reg,unsigned char *buf,unsigned char length)
{
unsigned char wbuf=reg;
struct spi_message m;
struct spi_transfer t[2] = {
{
.tx_buf = &wbuf,
.len = 1,
},
{
.rx_buf = buf,
.len = length,
}
};
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
return spi_sync(nrf24xx_spi, &m);
}
void Active_Nrf24l10(unsigned char cmd)
{
gpio_set_value(DEV2_CE_PIN,cmd);
}
unsigned char Nrf24l0_ReceiveBuf(unsigned char *buf)
{
unsigned char status = 0;
SPI1_Read_Reg(STATUS,&status);
SPI1_Write_Register(WRITE_REG1 +STATUS ,status);//清除相应的标志位
if(status & RX_OK)
{
SPI1_ReadBuf(RD_RX_PLOAD,buf,RX_PLOAD_WIDTH_32);
SPI1_Write_Register(FLUSH_RX,0xff);
return RX_OK; //接收成功返回RX_OK
}
return OTHER_ERROR;
}
unsigned char Nrf24l10_SendBuf(unsigned char* data_buffer, unsigned char length)
{
unsigned char status = 0;
Active_Nrf24l10(0);
SPI1_SendBuf(WR_TX_PLOAD,data_buffer,TX_PLOAD_WIDTH_32);//写数据到TX BUF 32个字节
// SPI1_SendBuf(WR_TX_PLOAD,data_buffer,length);//写数据到TX BUF 32个字节
Active_Nrf24l10(1);
while(1 == Nrf24l10_Irq())//等待发送完成事件
{
//printk("Nrf24l10_Irq..............\n");
schedule_timeout(HZ/50);//HZ=100 , 每10ms jiffies+1
}
SPI1_Read_Reg(STATUS,&status);
SPI1_Write_Register(WRITE_REG1 +STATUS ,status);//清除相应的标志位
if(status & TX_OK)
{
return TX_OK; //接收成功返回RX_OK
}else if(status & MAX_RET_FLAG)
{
SPI1_Write_Register(FLUSH_TX,0xff);
return MAX_RET_FLAG; //否则返回ERROR
}
return OTHER_ERROR;
}
unsigned char Nrf24l10_Irq(void)
{
return gpio_get_value(DEV2_CE_PIN);
}
..................................................................................下面直接给出STM32的源码.........................................................................
#include "NRF24L10_Driver.h"
#include "delay.h"
unsigned char TX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01}; //发送地址
unsigned char RX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01};
/*
初始化Nrf24l10的端口,作为SPI输出
STM32F10X NRF24L10
PA2 IRQ
PA3 CE (Chip Enable)高电平有效,低电平时用来设置Nrf24l10高电平时传输数据
SPI1_NSS PA4 CSN (Chip Select Not) 片选引脚低电平有效
SPI1_SCK PA5 SCK 主模式下 推挽复用输出
SPI1_MISO PA6 MISO 全双工模式/主模式下 浮空输入或带上拉输入
SPI1_MOSI PA7 MOSI 全双工模式/主模式 推挽复用输出
*/
void Nrf24l10_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*开启GPIOA的时钟和复用功能的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
// SPI1_SCK PA5 SCK 主模式下 推挽复用输出
// SPI1_MOSI PA7 MOSI 全双工模式/主模式 推挽复用输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用功能(推挽)输出 SPI2
GPIO_Init(GPIOA, &GPIO_InitStructure);
//SPI1_MISO PA6 MISO 全双工模式/主模式下 浮空输入或带上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //复用功能(推挽)输出 SPI2
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PA3 CE (Chip Enable)高电平有效,低电平时用来设置Nrf24l10高电平时传输数据
// SPI1_NSS PA4 CSN (Chip Select Not) 片选引脚低电平有效
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*IRQ引脚配置为输入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*
NRF24L10片选信号,低电平有效,cmd=1选中,=0取消选中
*/
void Chip_SelectOrNot(unsigned char cmd)
{
if(cmd==0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
}else{
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
}
}
/*
激活NRF24L10的数据传输功能cmd=1,激活,=0时候数据传输功能禁止,但是此模式下可用来配置NRF24L10功能
*/
void Active_Nrf24l10(unsigned char cmd)
{
if(cmd==1)
{
GPIO_SetBits(GPIOA,GPIO_Pin_3);
}else{
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
}
/*
Nrf24l10的IRQ引脚是否低电平
*/
unsigned char Nrf24l10_Irq(void)
{
return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2);
}
void Nrf24L10_SPI1_Configuration(void)
{
SPI_InitTypeDef SPI_InitStructure;
/*开启外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/*设置SPI1的工作模式*/
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; //时钟极性 空闲状态时,SCK保持低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //时钟相位 数据采样从第一个时钟边沿开始
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件产生NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //波特率控制 72MHz/16 = 4.5MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据高位在前
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC多项式寄存器初始值为7
SPI_Init(SPI1, &SPI_InitStructure);
/* 使能SPI2 */
SPI_Cmd(SPI1, ENABLE);
}
void NRF24L10_Init(void)
{
Nrf24l10_GPIO_Init();
Nrf24L10_SPI1_Configuration();
}
/*
SPI1发送一个字节的数据
*/
unsigned char SPI1_Send_Byte(unsigned char data)
{
/* 循环检测发送缓冲区是否是空 */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
{
Delay_us(100);
}
SPI_I2S_SendData(SPI1, data);
/* 等待接收数据,循环检查接收数据缓冲区 */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
{
Delay_us(100);
}
/* 返回读出的数据 */
return SPI_I2S_ReceiveData(SPI1);
}
/*
SPI1向指定寄存器发送一字节的数据
*/
unsigned char SPI1_Write_Register(unsigned char reg,unsigned char data)
{
unsigned char ret =0;
Chip_SelectOrNot(1);
SPI1_Send_Byte(reg);
ret = SPI1_Send_Byte(data);
Chip_SelectOrNot(0);
return ret;
}
/*
SPI1发送一个缓冲区
*/
unsigned char SPI1_SendBuf(unsigned char reg,unsigned char *buf,unsigned char length)
{
unsigned char status=0;
unsigned char i=0;
Chip_SelectOrNot(1);
status = SPI1_Send_Byte(reg);
for(i=0; i
新手整整搞了3天才调通,还有有些地方说的不好,见谅。就当是记笔记。