基于MSP430的nRF905无线模块SPI发送实验

一、实验概述与核心目标

1. 实验定位

本实验基于TI MSP430系列单片机与Nordic nRF905无线射频芯片,利用SPI接口(通常为GPIO模拟SPI,因MSP430低端机型无硬件SPI)实现无线数据的发送。实验核心是掌握nRF905的ShockBurst™突发传输模式与SPI单字节写入时序。

2. 核心功能

  • IO模拟SPI:通过普通GPIO引脚翻转,模拟SPI的SCK(时钟)、MOSI(主发从收)、MISO(主收从发)时序。
  • nRF905初始化:通过SPI向nRF905写入配置字(频段、地址、CRC校验等)。
  • 无线数据发送:将待发送数据写入nRF905发送寄存器,拉高控制引脚,触发射频发射。

二、硬件设计方案

1. 核心硬件选型

模块 型号 关键参数
主控MCU MSP430G2553 / F5529 低功耗16位RISC内核,支持IO模拟SPI
无线模块 nRF905 433/868/915MHz ISM频段,最大50kbps,支持自动CRC与地址匹配
晶振 16MHz无源晶振 nRF905射频基准时钟

2. 引脚连接(IO模拟SPI方案)

由于MSP430G2系列等部分型号无硬件SPI,需使用4个普通GPIO模拟SPI时序。连接方式如下:

nRF905引脚 MSP430引脚 功能定义 IO方向
SCK P1.5 (自行定义) SPI时钟线 MSP430输出
MOSI P1.7 (自行定义) SPI主发从收(数据发送) MSP430输出
MISO P1.6 (自行定义) SPI主收从发(读取状态) MSP430输入
CSN P1.4 (自行定义) SPI片选(低电平有效) MSP430输出
TRX_CE P2.0 (自行定义) 发射/接收使能(高电平有效) MSP430输出
TX_EN P2.1 (自行定义) 发射模式使能(高电平有效) MSP430输出
PWR_UP P2.2 (自行定义) 模块上电控制(高电平有效) MSP430输出
DR P2.3 (自行定义) 数据就绪/发送完成中断引脚 MSP430输入

注意:以上引脚分配为通用约定,实际可根据MSP430的Port资源灵活调整。

三、软件设计与核心代码(基于IO模拟SPI)

1. 软件执行流程

  1. MSP430初始化:配置GPIO的输入/输出方向,关闭看门狗。
  2. SPI模拟初始化:将SCK、CSN、MOSI置为高电平(SPI空闲状态)。
  3. nRF905配置:拉低CSN,通过SPI循环写入11字节的配置字(设定433MHz、10dBm发射功率、4字节地址宽度等)。
  4. 发送模式切换:拉高TRX_CE并拉高TX_EN,使nRF905进入ShockBurst™发射模式。
  5. 数据打包发送:拉低CSN,发送“写发送载荷”指令,随后连续写入发送数据;写完后拉高CSN;最后拉高TRX_CE触发发送。

2. 核心代码实现(C语言)

2.1 IO模拟SPI单字节发送函数

/* 
 * 函数功能:模拟SPI主机向从机发送一个字节
 * 时序说明:CPOL=0, CPHA=0 (空闲时钟低电平,上升沿采样)
 * 引脚假定:SCK->P1.5, MOSI->P1.7, CSN->P1.4
 */
void SPI_SendByte(unsigned char data)
{
    unsigned char i;
    for (i = 0; i < 8; i++)  // 循环发送8位
    {
        if ((data & 0x80) != 0)  // 判断最高位是1还是0
        { 
            P1OUT |= BIT7;   // MOSI = 1 (发送高电平)
        } else { 
            P1OUT &= ~BIT7;  // MOSI = 0 (发送低电平)
        }
        P1OUT |= BIT5;     // SCK = 1 (制造上升沿,让从机采样接收数据)
        data <<= 1;         // 左移一位,准备发送下一位
        P1OUT &= ~BIT5;    // SCK = 0 (时钟回到低电平)
    }
}

2.2 nRF905配置函数(写入11字节配置字)

/* 全局配置字数组:设定nRF905工作参数 */
unsigned char RFConf[11] = {
    0x00,       // 配置命令字头
    0x6C,       // CH_NO: 频道设置,433.2MHz
    0x0E,       // 输出功率10dBm,开启自动重发,正常模式
    0x44,       // 接收/发送地址宽度为4字节
    0x10, 0x10, // 接收/发送数据宽度为16字节
    0xE7, 0xE7, 0xE7, 0xE7, // 设置接收端地址 (4字节,需与发送方一致)
    0xDE        // CRC允许,16位CRC校验,晶振16MHz
};

/* 
 * 函数功能:初始化nRF905,写入配置字
 */
void Config_nRF905(void)
{
    unsigned char i;
    P1OUT &= ~BIT4; // CSN = 0 (拉低片选,使能SPI通信) 
    
    for (i = 0; i < 11; i++)
    {
        SPI_SendByte(RFConf[i]); // 逐字节写入配置字 
    }
    
    P1OUT |= BIT4;  // CSN = 1 (拉高片选,关闭SPI通信)
}

2.3 nRF905无线发送主逻辑

/* 宏定义与全局变量 */
#define WTP  0x20  // nRF905指令:写发送载荷 (Write TX Payload)
#define WTA  0x22  // nRF905指令:写发送地址 (Write TX Address)
#define TRX_CE_BIT  BIT0 // 假定 TRX_CE 连接在 P2.0
#define TX_EN_BIT  BIT1 // 假定 TX_EN 连接在 P2.1

unsigned char TxBuffer[16] = "Hello MSP430!"; // 待发送的数据包

/* 
 * 函数功能:将指定缓冲区数据通过nRF905发送出去
 * 参数 len: 发送数据的长度(最大32字节)
 */
void nRF905_SendData(unsigned char *TxBuf, unsigned char len)
{
    unsigned char i;
    
    /* 步骤1:将nRF905设置为发射模式 */
    P2OUT &= ~TRX_CE_BIT; // TRX_CE = 0
    P2OUT |= TX_EN_BIT;   // TX_EN   = 1 (进入发射模式) 
    __delay_cycles(100);  // 延时约几十微秒,等待模式稳定 
    
    /* 步骤2:写入发送数据 */
    P1OUT &= ~BIT4;  // CSN = 0
    SPI_SendByte(WTP); // 发送“写发送载荷”指令 
    for (i = 0; i < len; i++)
    {
        SPI_SendByte(TxBuf[i]); // 逐个字节写入数据
    }
    P1OUT |= BIT4;   // CSN = 1
    
    __delay_cycles(10); // 微小延时
    
    /* 步骤3:写入接收端地址(必须与接收方配置的地址完全一致)*/
    P1OUT &= ~BIT4;  // CSN = 0
    SPI_SendByte(WTA); // 发送“写发送地址”指令 
    for (i = 0; i < 4; i++)
    {
        SPI_SendByte(RFConf[4+i]); // 写入前面配置好的4字节地址
    }
    P1OUT |= BIT4;   // CSN = 1
    
    /* 步骤4:拉高TRX_CE,触发数据发送 */
    P2OUT |= TRX_CE_BIT; // TRX_CE = 1 (开始发射数据) 
    __delay_cycles(1000); // 等待发送完成(或使用DR引脚查询中断)
    
    /* 步骤5:发送完毕,拉低TRX_CE,回到待机模式 */
    P2OUT &= ~TRX_CE_BIT; // TRX_CE = 0
}

四、主程序调用示例

#include <msp430.h>

/* 此处需包含上述定义的宏、全局变量及函数声明 */

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;   // 关闭看门狗 
    
    /* 1. 初始化GPIO方向 */
    P1DIR |= (BIT4 + BIT5 + BIT7);  // P1.4(CSN), P1.5(SCK), P1.7(MOSI) 设为输出
    P1DIR &= ~BIT6;                 // P1.6(MISO) 设为输入
    P2DIR |= (TRX_CE_BIT + TX_EN_BIT); // P2.0/P2.1 设为输出
    P2OUT &= ~(TRX_CE_BIT + TX_EN_BIT); // 默认拉低控制引脚
    
    /* 2. 初始化SPI默认电平 */
    P1OUT |= (BIT4 + BIT5); // CSN=1 (默认不选中), SCK=1 (空闲高电平视情况,这里与函数内逻辑保持一致即可)
    
    /* 3. 上电并配置nRF905 */
    P2OUT |= BIT2;     // PWR_UP = 1 (给nRF905上电) 
    __delay_cycles(1000); // 等待模块上电稳定
    Config_nRF905();   // 写入配置字
    
    /* 4. 循环发送数据 */
    while(1)
    {
        nRF905_SendData(TxBuffer, 16); // 发送16字节数据
        __delay_cycles(1000000);       // 延时约几百毫秒,避免刷屏式发送
    }
}

参考代码 MSP430 无线模块nRF905 SPI接口发送实验 www.youwenfan.com/contentcnt/133664.html

五、关键注意事项

1. SPI时序与电平配合

  • CPOL/CPHA匹配:MSP430模拟的SPI时序必须严格遵循nRF905的要求(一般为模式0:SCK空闲低电平,上升沿采样)。
  • 建立与保持时间:在SCK的上升沿和下降沿之间,需加入微小的空语句延时(如__delay_cycles(1)),确保数据在nRF905内部建立时间和保持时间的容限内。

2. 电源与模式切换

  • 上电等待PWR_UP拉高后,nRF905内部的晶体振荡器起振需要一定时间(约几毫秒),务必加延时。
  • 模式切换延时:当改变TRX_CETX_EN的电平时,nRF905的模式切换需要约650ns~1.5us的硬件稳定时间,代码中需微量延时。

3. 地址一致性

  • 收发地址必须完全相同:发送方通过WTA指令写入的4字节地址,必须与接收方配置的接收地址(RFConf数组的第5到第8个元素)完全一致,否则接收方会自动丢弃数据包。
posted @ 2026-04-15 18:31  小前端攻城狮  阅读(7)  评论(0)    收藏  举报