您好!
我已经将一个 MSP430F2013与一个 nRF24L01模块连接。 SPI 设置都正确且工作正常、因为我能够写入和读取射频模块的寄存器。
但是、当来自另一个射频模块的数据到达时、我无法读取它。 它报告所有零。 无论是 MSP 侧还是射频模块侧的问题、我都不会感到惊讶。
我使用的硬件是- ezMSP430开发套件。 是否有人遇到过类似的问题?
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
我已经将一个 MSP430F2013与一个 nRF24L01模块连接。 SPI 设置都正确且工作正常、因为我能够写入和读取射频模块的寄存器。
但是、当来自另一个射频模块的数据到达时、我无法读取它。 它报告所有零。 无论是 MSP 侧还是射频模块侧的问题、我都不会感到惊讶。
我使用的硬件是- ezMSP430开发套件。 是否有人遇到过类似的问题?
您好、Bruce、
感谢您的回答! 状态字节正在被正确读取、它只是被读取为零的数据。 下面是供您参考的代码,请原谅一些愚蠢的事情,比如使用循环来获得延迟,我针对 原型执行了快速而肮脏的实施:)一旦 RF 部件被清除,它就会被清理。
/*
*文件名:main.c
*
*
#include
#include "types.h"
//nRF24L01寄存器地址-总计23 (十进制)/0x17 (十六进制)
//------------------------------------------
#define REG_CONFIG 0x00 //配置:屏蔽中断- RX DR、TX DS 和 MAX RT over、启用 CRC、CRC 类型、PWR UP、PRIM_RX/TX
#define REG_EN_AA 0x01 //启用自动 ACK
#define REG_EN_RXADDR 0x02 //启用 RX 管道
#define REG_SETUP_AW 0x03 //设置地址宽度- 1到5个字节
#define REG_SETUP_RETR 0x04 //设置编号 重试次数
#define REG_RF_CH 0x05 //设置射频通道
#define REG_RF_SETUP 0x06 //射频参数设置:PLL 锁定、数据速率、功率 LVL
#define REG_STATUS 0x07 //状态- RX 数据就绪、TX 数据发送、MAX_RT、RX_P_NO (数据到达的 RX 管道)、TX_FULL
#define REG_Observ_TX 0x08 //观察 TX 参数数据包丢失计数、重新发送 PKT 计数
#define REG_CD 0x09 //载波检测
#define REG_RX_ADDR_P0 0x0A //默认0XE7E7E7
#define REG_RX_ADDR_P1 0x0B //默认值0XC2C2C2C2C2C2
#define REG_RX_ADDR_P2 0x0C //默认 LSB - OXC3,其余保持与 P1相同
#define REG_RX_ADDR_P3 0x0D //默认 LSB - 0xc4
#define REG_RX_ADDR_P4 0x0E //默认 LSB - 0XC5
#define REG_RX_ADDR_P5 0x0F //默认 LSB - 0XC6
#define REG_TX_ADDR 0x10 //默认0XE7E7E7
#define REG_RX_PW_P0 0X11 //有效载荷宽度管道0 -默认值0 MAX 32
#define REG_RX_PW_P1 0x12 //与上面的 pipe1相同
#define REG_RX_PW_P2 0x13 //与上面的 PIPE2相同
#define REG_RX_PW_P3 0x14 //与上面的 PIPE3相同
#define REG_RX_PW_P4 0X15 //与上述 PIPE4相同
#define REG_RX_PW_P5 0x16 //与上述 PIPE5相同
#define FIFO_STATUS 0x17 //状态- TX_REuse、TX_FULL、TX_EMPTY、RX_FULL、RX_EMPTY
//寄存器读取和写入命令掩码
//同时使用寄存器读取和写入命令,这些命令与5位命令一起使用
//寄存器地址以获取相应的寄存器读/写命令
///---------------------------------------------------------
#define R_REG_CMD_MASK 0x00
#define W_REG_CMD_MASK 0x20
//NRF24配置掩码
///------------------
#define NRF_CFG_PWRUP 0x02
#define NRF_CFG_PWRDN 0xFD
#define NRF_CFG_Prim_RX 0xFE
#define NRF_CFG_Prim_TX 0x01
#define NRF_CFG_ENABLE_CRC 0x08
#define NRF_CFG_DISABLE_CRC 0xF7
#define NRF_CFG_CRC_PHASE_1B 0x04
#define NRF_CFG_CRC_PHASE_2B 0xFB
//射频收发器的地址宽度
///----------------------------
#define NRF_AW_3B 0x01
#define NRF_AW_4B 0x10
#define NRF_AW_5B 0x11
//nRF24L01芯片选择和启用掩码
///------------------------------
#define NRF_CS_MASK 0xEF //低电平有效位 P1.4
#define NRF_CE_MASK 0x08 //高电平有效位 P1.3
//启用自动确认掩码
///------------------
//读取写操作指令
///----------------------------
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
//数据包位置索引
///------------------
#define ADDR_POS 0x01
#define context_POS 0x02
#define RMT_CMD_POS 0x03
#define DATA_HI_POS 0x04
#define DATA_LO_POS 0x05
#define CMD_OFF 0x00
#define CMD_ON 0x01
#define self_ADDR 0x01 //这是逻辑地址,每个从机不同
#define broadcast_ADDR 0xFF //这是广播地址,表示所有从机都应对数据执行操作。
#define ADDR_width 0x05 //使用5字节地址
主灯发出//远程命令
///----------------------------
#define RMT_CMD_BTN_State_Change 0x01
#define RMT_CMD_SET_Brightness 0x02
/*全球定义*/
//--------
unsigned char g_rxBuf[8]; //全局缓冲器可接收来自 NRF 模块的所有内容,大小适合最大有效负载长度
unsigned char g_txBuf[8]; //global buffer、用于将所有内容发送到 NRF 模块、大小适合最大有效载荷长度
unsigned char g_payloadBuf[8]; //global buffer、用于保存从主器件接收到的数据、大小适合最大有效载荷长度
//由于我们将使用逻辑寻址,所有从属节点将具有相同的物理地址,但有效负载将是
//包含用于区分各个节点的逻辑地址
const unsigned char g_txAddress[6]={"10000"};
const unsigned char g_rxAddress[6]={"20000"};
uint8 g_datalelength = 1; //长度包括命令字节。 因此、最小值为1
uint8 g_transfer_complete = 0; //表示 MSP 和无线电之间的 SPI 传输完成
uint8 g_data_ready = 0;
uint8 g_buf_index = 0;
uint8 g_init_done = 0;
const uint8 g_payloadWidth = 7; //最大有效载荷大小为32字节,但我们的数据仅为7字节。
//函数原型
//--------
void Init_Port1 (void);
void Init_SPI (void);
void Init_PWM (void);
void Init_Radio (void);
void process_Master_Command (void);
void Radio_CE_Enable (void);
void Radio_CE_Disable (void); //停止 SPI 通信
void Radio_CS_Enable (void);
void Radio_CS_Disable (void); //停止 SPI 通信
void Radio_WriteRegister (UINT8 regName、UINT8长度);
void Radio_ReadRegister (uint8 regName、uint8 len);
/**
* main.c
*
int main (空)
{
volatile unsigned int i;
WDTCTL = WDTPW + WDTHOLD; //停止看门狗计时器
//首先初始化内部外设
init_Port1();
init_spi();
init_pwm ();
/*在此处启用常规中断,因为否则我们将无法使用
* Radio_Init 中的 SPI 中断!!
*
_BIS_SR (GIE);
init_Radio();
while (1)
{
unsigned int i;
//if (g_data_ready){ //interrupt -data 已到达、已注释为使用轮询模式进行测试、因为 IRQ 不会变为低电平:(
for (i=0;i<0x1ff;i++);
Process_Master_Command ();
// g_data_ready = 0;
P1OUT &=~BIT0;
//}
}
}
//中断服务例程
///------------------
// USI 中断服务例程
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector=USI_vector
_interrupt void universal_serial_interface (void)
#Elif defined (_GNU_)
void __attribute__((interrupt (USI_vector))) universal_serial_interface (void)
其他
错误编译器不受支持!
#endif
{
//将接收到的数据读出到缓冲区中,
//在它被下一个写入前
G_rxBuf[g_buf_index]= USISRL;
//检查是否是上电后的第一次或者是否正在进行事务处理
g_datalelength --;
if (g_datalelength = 0){
G_buf_index = 0;
G_TRANSFER_COMPLETE = 1; //传输完成
if (USICTL1 & 0x01)
USICTL1 &=~USIIFG;
}
否则{ //需要发送更多数据
G_buf_index++;
USISRL = g_txBuf[g_buf_index];
USICNT = 8; //重载计数器
}
}
//Port1 GPIO 引脚中断服务例程
#pragma vector = Port1_vector
_interrupt void InterruptVectorPort1 ()
{
P1IFG &=~BIT1; //清除中断标志
P1OUT |= BIT0;
G_DATA_READY = 1; //主器件已传入
}
//中断服务例程结束
//此处显示所有功能代码
/
*函数:Init_Port1
*此函数将给定数量的字节写入指定的寄存器
在 nRF24L01内通过 SPI 总线
(二 /
空 Init_Port1 (空)
{
//位配置
// P1.7::P1.6:P1.5:P1.4:P1.3:P1.2:P1.1:P1.0
//输出 ::输入 ::输出 :: 输出 ::输出 ::输入:: 输出
// MOSI:::MISO:SCK ::CSn :CE :PWM ::IRQ :LED
P1DIR |= BIT4 + BIT3 + BIT2 + BIT0; // P1.4、P1.3、P1.2和 P1.0输出
P1REN |= BIT4;//+ BIT1; //为 P1.4 (CSn)和 P1.1 (IRQ)启用上拉
P1IE |= BIT1; //启用 port1.1中断
P1IES |= BIT1; //高到低边沿或下降边沿,因为 nRF24的 IRQ 信号为低电平有效
//初始状态设置
P1OUT |= BIT4; //驱动高电平 P1.4 - CSn 低电平有效
P1OUT &=~BIT3; //将 P1.3驱动为低电平、CE 为高电平有效
P1OUT &=~BIT2; //将 P1.2驱动为低电平、MOSFET 默认处于关闭状态
P1OUT &=~BIT0; //将 P1.0驱动为低电平、LED 为高电平有效
}
/
*函数:Radio_CE_Enable
*此函数将给定数量的字节写入指定的寄存器
在 nRF24L01内通过 SPI 总线
(二 /
空 Init_SPI (空)
{
USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE;//端口、SPI 主控
USICTL1 |= USIIE + USICKPH; //计数器中断、标志保持置位、nRF24所需的时钟相位为1
USICKCTL = USIDIV_4 + USISSEL_2; ///16 SMCLK
USICTL0 &=~USISWRST; // USI 被释放以运行
}
/
*函数:Init_PWM
*此函数将给定数量的字节写入指定的寄存器
在 nRF24L01内通过 SPI 总线
(二 /
空 Init_PWM (空)
{
#if 0
P1DIR |= 0x04; // P1.2
P1SEL |= 0x04; // P1.2配置为备用功能1.
CCR0 = 51-1; // PWM 周期
CCTL1 = OUTMOD_7; // CCR1复位/置位
CCR1 = 384; // CCR1 PWM 占空比
TACTL = tassel_2 + MC_1; // SMCLK、向上计数模式
#endif
}
/
*函数:Config_Radio
*此函数将给定数量的字节写入指定的寄存器
在 nRF24L01内通过 SPI 总线
(二 /
空 Init_Radio (空)
{
unsigned int i;
RADIO_CS_Disable ();
RADIO_ReadRegister (((UINT8) REG_CONFIG、2);
G_txBuf[1]= 0x01;
RADIO_WriteRegister (((UINT8) REG_CONFIG、2); //PWR_UP = false、MODE = PRIM_RX
for (i = 0xff;i;i--);
RADIO_ReadRegister (((UINT8) REG_CONFIG、2);
G_txBuf[1]= 0x03;
RADIO_WriteRegister (((UINT8) REG_SETUP_AW、2); //地址宽度-5字节
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_SETUP_AW、2);
for ( i = 0;<ADDR_WIDTH ;i++ ){
G_txBuf[i+1]= g_txAddress[i];
}
RADIO_WriteRegister ((((UINT8) REG_TX_ADDR、6);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_TX_ADDR、6);
RADIO_WriteRegister ((((UINT8) REG_RX_ADDR_P0、6); //这似乎有点令人困惑、但 Tx 地址和 Rx 管道0地址是相同的
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_RX_ADDR_P0、6);
G_txBuf[1]= 0x07; //将有效载荷大小设置为7字节
RADIO_WriteRegister ((((UINT8) REG_RX_PW_P0、2);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_RX_PW_P0、2);
for ( i = 0;i< ADDR_width;i++){
G_txBuf[i+1]= g_rxAddress[i];
}
RADIO_WriteRegister ((((UINT8) REG_RX_ADDR_P1、6);//和 Rx 管道1地址为
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_RX_ADDR_P1、6);
G_txBuf[1]= 0x07;
RADIO_WriteRegister ((((UINT8) REG_RX_PW_P1、2);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_RX_PW_P1、2);
G_txBuf[1]= 0x00;
RADIO_WriteRegister (((UINT8) REG_EN_AA、2);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_EN_AA、2);
G_txBuf[1]= 0x03;
RADIO_WriteRegister ((((UINT8) REG_EN_RXADDR、2);
for (i = 0xff;i;i--);
G_txBuf[1]= 0x5F;
RADIO_WriteRegister (((UINT8) REG_SETUP_RETR、2);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_SETUP_RETR、2);
G_txBuf[1]= 0x4C; //选择射频通道76
RADIO_WriteRegister (((UINT8) REG_RF_CH、2);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_RF_CH、2);
G_txBuf[1]= 0x07; //选择射频数据速率1Mbps 和功率0dBm
RADIO_WriteRegister (((UINT8) REG_RF_Setup、2);
for (i = 0xff;i;i--);
RADIO_ReadRegister ((((UINT8) REG_RF_Setup、2);
RADIO_WriteRegister (((UINT8) FLUSH_TX、1);
for (i = 0xff;i;i--);
RADIO_WriteRegister (((UINT8) FLUSH_RX、1);
G_txBuf[1]= 0x43; //仅配置 RX_DR 中断
RADIO_WriteRegister (((UINT8) REG_CONFIG、2); //PWR_UP = true、MODE = PRIM_RX
for (i = 0xff;i;i--);
RADIO_ReadRegister (((UINT8) REG_CONFIG、2);
RADIO_CE_Enable (); //启动接收模式- PRIM_RX
}
/
*函数:Radio_ReadPayload
*此函数读取从主设备发出的用于打开/关闭 LED 的命令消息
或调节亮度
*参数:
(二 /
unsigned int Radio_ReadPayload (空)
{
unsigned char status;
unsigned int i;
RADIO_ReadRegister (REG_STATUS、2);
状态= g_rxBuf[0];
if (status & 0x40) //if data received:RX_DR 被置位、
{
if (status & 0x02){ //pipe number = 1。
//现在读取有效载荷
G_txBuf[0]= R_RX_PAYLOAD;
G_datalelength = 8;
USISRL = g_txBuf[0];
USICNT = 8;
while (!g_transfer_complete){;}
对于(i = 0;i < g_payloadWidth;i++){
G_payloadBuf[i]= g_rxBuf[i+2]; //将内容传输到有效负载寄存器、因为 Tx 缓冲区很快就会被覆盖。
}
G_txBuf[1]=状态| 0x70; //复位中断标志
RADIO_WriteRegister (REG_STATUS、2);
for (i = 0;i< 0xff;i++);
返回 g_payloadWidth;
}
返回0;
}
其他
返回0;
}
#if 0
/
*函数:Radio_SendPayload
*此函数向主器件发送消息、如灯的当前状态、
或亮度级别。 解决方案。
(二 /
unsigned int Radio_SendPayload (nrf_WriteTypeDef writeType、unsigned char* txBuf、unsigned int numBytes)
{
//现在我们没有任何东西要传输到主设备,因此没有实现
返回0;
}
#endif
/
*函数:Radio_CS_Enable
*此函数将芯片选择信号置为有效以启用对 nRF24芯片的 SPI 读取/写入
*参数:无
*返回:无
(二 /
void Radio_CS_Enable()
{
//将 CSn 引脚驱动为低电平;
P1OUT &=~BIT4;
}
/
功能:Radio_CS_Disable
*此函数将芯片选择信号置为无效以禁用对 nRF24芯片的 SPI 读取/写入
*参数:无
*返回:无
(二 /
void Radio_CS_Disable()
{
//将 CSn 引脚驱动为高电平;
P1OUT |= BIT4;
}
/
*函数:Radio_CE_Enable
*此函数将芯片使能信号置为有效以控制传输或接收
*在 Prim_TX 模式下、我们将 CE 线路保持在低电平、直到我们希望发送某个内容。 进行选择
*为了发送、我们将负载转储到 TX_PLD 寄存器中并将该引脚置为 短路状态
*持续时间。
*在 PRIM_RX 模式下、该引脚必须始终保持高电平才能监听传输。
*参数:无
*返回:无
(二 /
void Radio_CE_Enable()
{
//将 CSn 引脚驱动为低电平;
P1OUT |= BIT3;
}
/
功能:Radio_CE_Disable
*此函数将给定数量的字节写入指定的寄存器
在 nRF24L01内通过 SPI 总线
(二 /
void Radio_CE_Disable ()
{
//将 CSn 引脚驱动为高电平;
P1OUT &=~BIT3;
}
/
*函数:Radio_ReadRegister
*此函数从指定寄存器读取给定数量的字节
在 nRF24L01内通过 SPI 总线。 在这里、我们只需启动操作
*主传输发生在 USI 中断服务例程内
*我们始终使用全局 g_txBuff 缓冲区进行传输
(二 /
空 Radio_ReadRegister (UINT8 regName、UINT8 len)
{
unsigned int i;
RADIO_CS_Enable(); //启动 SPI 通信
对于(i = 0;i < 128;i++);
G_TRANSFS_COMPLETE = g_Buf_INDEX = 0; //将标志设置为 false
G_txBuf[0]= regName |(UINT8) R_REG_CMD_MASK; //使用寄存器地址设置寄存器读取屏蔽
G_datalelength = len; //要传输的字节数
USISRL = g_txBuf[0]; //将第一个字节加载到 USI 数据寄存器中
USICNT = 8; //加载位数来启动传输
while (!g_transfer_complete)
{ ; }//wait for the flag to be set (等待标志设置)
G_TRANSFER_COMPLETE = 0;
RADIO_CS_Disable ();
对于(I = 0;I < 128;I++); //停止 SPI 通信
}
/
*函数:Radio_WriteRegister
*此函数将给定数量的字节写入指定的寄存器
在 nRF24L01内通过 SPI 总线
*我们始终使用全局 g_txBuff 缓冲区进行传输
(二 /
空 Radio_WriteRegister (UINT8 regName、UINT8 len)
{
unsigned int i;
RADIO_CS_Enable(); //启动 SPI 通信
for (i = 0x7f;i;i--);
G_TRANSFS_COMPLETE = g_Buf_INDEX = 0;
G_datalelength = len;//将标志设置为 false
G_txBuf[0]= regName |(UINT8) W_REG_CMD_MASK;
USISRL = g_txBuf[0];
USICNT = 8; //加载位数来启动传输
while (!g_transfer_complete)
{ ; }//wait for the flag to be set (等待标志设置)
G_TRANSFER_COMPLETE = 0;
RADIO_CS_Disable (); //启动 SPI 通信
for (i = 0x7f;i;i--);
}
/
*函数:Process_Master_Command
*此函数处理从主器件接收到的命令。
*命令可以是打开/关闭类型和调光级别设置
(二 /
void proc_Master_Command (void)
{
uint8 addr = g_rxBuf[ADDR_POS];
if (!Radio_ReadPayload()){
if ((addr =broadcast_ADDR)||(addr =self_ADDR)) //如果它是宽幅广播消息
{
switch (g_payloadBuf[RMT_CMD_POS]){
案例1:
if (g_rxBuf[DATA_LO_POS]== CMD_ON)
P1OUT |= BIT2; //打开灯
其他
P1OUT &=~BIT2; //关闭灯
中断;
案例2:
中断;
}
}
}
}
/
*函数:LED_BrightnessControl
*此函数根据从主器件接收到的设置来改变 PWM 占空比。
*亮度将转换为 PWM
(二 /
void LED_BrightnessControl (内部亮度)
{
//to do
}
此致
Sreenivasa Chary
您好、Sreenivasa、
为了检查问题是在 MSP430侧还是在 NRE24L01侧、您可以参考代码示例、其中 msp430x20x3_USI_02、msp430x20x3_USI_03、msp430x20x3_USI_04 和 msp430x20x3_USI_05 都是与 SPI 接口相关的代码示例。
http://dev.ti.com/tirex/explore/node?node=AP2kp.Wkb-aPCeyAi0c3ag__IOGqZri__LATEST
此致
Johnson