freetech

kinetis下的NRF24L01+通信例程

0
阅读(8075)

有了前面的SPI例程,我们再来看一个实际应用SPI的例子。NRF24L01是工作在2.4GHz公共频段的射频芯片,其接口是SPI的,虽然kinetis的SPI有自动片选功能,但每发完一串比特流(本例中是1字节)片选信号要变成一次无效电平,NRF24L01要求同一命令和数据中间片选信号要一直有效,故本例中用GPIO来做片选。NRF24L01+模块只要芯片是NRF24L01程序上就兼容。笔者用的是这种:

image

//main.c

/*
* main implementation: use this 'C' sample to create your own application
*
*/

#include <stdio.h>

#include "derivative.h" /* include peripheral declarations */
#include "NRF24L01.h"
/*-----------------------------------------------------------------------------
   Global Defines
------------------------------------------------------------------------------*/
unsigned char send_dat;
unsigned char send_flag=0;
void init_CPU (void);
void delayms(unsigned short    dly);//当dly=1时,延时的时间是1ms  4MHz晶震
void INIT_io(void);
void RX_Mode(void);
void TX_Mode(void);

//------------------------------------------------------
unsigned char t20ms;
void GPIO_Init()
{
    SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK;
    PORTA_PCR26=(PORT_PCR_MUX(1));
    PORTA_PCR27=(PORT_PCR_MUX(1));
    PORTA_PCR28=(PORT_PCR_MUX(1));
    PORTA_PCR29=(PORT_PCR_MUX(1));
    GPIOA_PDDR = (1<<26) | (1<<27) | (1<<28) | (1<<29);
}
void PIT0_init(void)
{
    SIM_SCGC6 |= 0x00800000;
    PIT_MCR = 0x00;
    PIT_TCTRL0 = 0x00;
    PIT_TFLG0 = 0x01;
    PIT_LDVAL0 = 10000000;
    NVICISER2 |= 0x10;//使能中断NVICISERn=m,其中n=84/32,m=84%32
    PIT_TCTRL0 = 0x03;
}
void delay(void)//
{
    unsigned int i;
    for(i=0 ; i<200 ; i++);
}
void delayms(unsigned short    time)//
{
    SIM_SCGC6 |= 0x00800000;
    PIT_MCR = 0x00;
    PIT_TCTRL1 = 0x00;
    PIT_TFLG1 = 0x01;//清中断标识
    PIT_LDVAL1 = 20000 *time;
    PIT_TCTRL1 = 0x01;//开始计数
    while(PIT_TFLG1 == 0);//未溢出时一直等待
    PIT_TFLG1 = 0x01;//清中断标识
    PIT_TCTRL1 = 0;
}
int main(void)
{
    unsigned char tmp;
    GPIO_Init();
    NRF24L01_init();
    delayms(200);
    PIT0_init();
    RX_Mode();
    send_flag=0;
    printf("Hello (Kinetis) World in 'C' from MK60DX256Z derivative! \n\r");
    for(;;)
    {       
        if(send_flag==1)
        {
            Buffer[0]=80;
            Buffer[1]=02;
            Buffer[2]=send_dat;
            TX_Mode();            // set TX Mode and transmitting
            send_flag=0;
        }
    }
    return 0;
}
void PIT_CH0_ISR(void)
{
    static unsigned int val=1;
    PIT_TFLG0 = 1;
    GPIOA_PDOR = val << 26;
    send_dat = (unsigned char)val;
    val = val << 1;
    if(val == 0x10)
    {
      val = 1;
    }
    send_flag = 1;
}

//nrf24l01.c

#include "derivative.h" /* include peripheral declarations */
#include "NRF24L01.h"

unsigned char TX_ADDRESS[TX_ADR_WIDTH]  = {0x34,0x43,0x10,0x10,0x01}; // Define a static TX address
unsigned char     Buffer[]={
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
};

//------------------------------------------------------
/************************SPI初始化函数*******************************/
void SPI_Init(void) {
    SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
    SIM_SCGC6 |= SIM_SCGC6_SPI1_MASK;   
    PORTB_PCR17 = PORT_PCR_MUX(2);
    PORTB_PCR16 = PORT_PCR_MUX(2);
    PORTB_PCR11 = PORT_PCR_MUX(2);
    //PORTB_PCR9 = PORT_PCR_MUX(2);
    SPI1_MCR = SPI_MCR_ROOE_MASK | SPI_MCR_PCSIS(2) | SPI_MCR_HALT_MASK;//0x01020001
    // SPI1_MCR: MSTR=1,CONT_SCKE=0,DCONF=0,FRZ=0,MTFE=0,PCSSE=0,ROOE=1,??=0,??=0,PCSIS=2,DOZE=0,MDIS=0,DIS_TXF=1,DIS_RXF=1,CLR_TXF=1,CLR_RXF=1,SMPL_PT=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,HALT=1
    SPI1_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_ROOE_MASK | SPI_MCR_PCSIS(2) | SPI_MCR_DIS_TXF_MASK | SPI_MCR_DIS_RXF_MASK | SPI_MCR_CLR_TXF_MASK | SPI_MCR_CLR_RXF_MASK | SPI_MCR_HALT_MASK; //Set Configuration register
    // SPI1_CTAR0: DBR=1,FMSZ=7,CPOL=0,CPHA=0,LSBFE=0,PCSSCK=1,PASC=1,PDT=1,PBR=1,CSSCK=0,ASC=0,DT=0,BR=0x0A
    SPI1_CTAR0 = SPI_CTAR_DBR_MASK | SPI_CTAR_FMSZ(7) | SPI_CTAR_PCSSCK(1) | SPI_CTAR_PASC(1) | SPI_CTAR_PDT(1) | SPI_CTAR_PBR(1) | SPI_CTAR_CSSCK(0x00) | SPI_CTAR_ASC(0x00) | SPI_CTAR_DT(0x0) | SPI_CTAR_BR(0x0A); //Set Clock and Transfer Attributes register
    // SPI1_SR: TCF=1,TXRXS=0,??=0,EOQF=1,TFUF=1,??=0,TFFF=1,??=0,??=0,??=0,??=1,??=0,RFOF=1,??=0,RFDF=1,??=0,TXCTR=0,TXNXTPTR=0,RXCTR=0,POPNXTPTR=0
    SPI1_SR = SPI_SR_TCF_MASK | SPI_SR_EOQF_MASK | SPI_SR_TFUF_MASK | SPI_SR_TFFF_MASK | SPI_SR_RFOF_MASK | SPI_SR_RFDF_MASK | SPI_SR_TXCTR(0) | SPI_SR_TXNXTPTR(0) | SPI_SR_RXCTR(0) | SPI_SR_POPNXTPTR(0); //Clear flags
    // SPI1_RSER: TCF_RE=0,??=0,??=0,EOQF_RE=0,TFUF_RE=0,??=0,TFFF_RE=0,TFFF_DIRS=0,??=0,??=0,??=0,??=0,RFOF_RE=0,??=0,RFDF_RE=0,RFDF_DIRS=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0
    SPI1_RSER = 0;  //Set DMA Interrupt Request Select and Enable register
    // SPI1_MCR: HALT=0
    SPI1_MCR &=  ~SPI_MCR_HALT_MASK;
}
/**************************************************
Function: SPI_RW();

Description:
  Writes one byte to nRF24L01, and return the byte read
  from nRF24L01 during write, according to SPI protocol  */
/**************************************************/
unsigned char SPI_RW(unsigned char dat)
{
    unsigned char tmp;
    {
        SPI1_PUSHR = SPI_PUSHR_PCS(2) | dat;
        while((SPI1_SR&SPI_SR_TFFF_MASK) == 0);
        while((SPI1_SR&SPI_SR_RFDF_MASK) == 0);
        tmp =SPI1_POPR;
        SPI1_SR = SPI_SR_TFFF_MASK | SPI1_SR&SPI_SR_RFDF_MASK;
    }
    return(tmp); // return read byte
}
/**************************************************
Function: SPI_RW_Reg();

Description:
  Writes value 'value' to register 'reg' */
/**************************************************/
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value)
{
    unsigned char status;
    unsigned char tmp;
    nRF24L01_CSNL;
    delay();
    status = SPI_RW(reg);      // select register
  tmp = SPI_RW(value);             // ..and write value to it..
    nRF24L01_CSNH;
    delay();
      return(status);            // return nRF24L01 status byte
}
/**************************************************
Function: SPI_Read();

Description:
  Read one byte from nRF24L01 register, 'reg'  */
/**************************************************/
unsigned char SPI_Read(unsigned char reg)
{
    unsigned char reg_val;
    unsigned char tmp;
    nRF24L01_CSNL;
    delay();
  tmp = SPI_RW(reg);            // Select register to read from..
      reg_val = SPI_RW(0);    // ..then read registervalue
    nRF24L01_CSNH;
    delay();
      return(reg_val);        // return register value
}
/**************************************************
Function: SPI_Read_Buf();

Description:
  Reads 'bytes' #of bytes from register 'reg'
  Typically used to read RX payload, Rx/Tx address */
/**************************************************/
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
    unsigned char status,byte_ctr;
    nRF24L01_CSNL;
    delay();
      status = SPI_RW(reg);               // Select register to write to and read status byte
    for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
        pBuf[byte_ctr] = SPI_RW(0);    // Perform SPI_RW to read byte from nRF24L01
    nRF24L01_CSNH;
    delay();
      return(status);                    // return nRF24L01 status byte
}
/**************************************************
Function: SPI_Write_Buf();

Description:
  Writes contents of buffer '*pBuf' to nRF24L01
  Typically used to write TX payload, Rx/Tx address */
/**************************************************/
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
    unsigned char status,byte_ctr;
    nRF24L01_CSNL;                           // Set nRF24L01_CSN low, init SPI tranaction
      delay();
    status = SPI_RW(reg);                        // Select register to write to and read status byte
      for(byte_ctr=0; byte_ctr<bytes; byte_ctr++) // then write all byte in buffer(*pBuf)
        status = SPI_RW(*pBuf++);           
    nRF24L01_CSNH;                                 // Set nRF24L01_CSN high again
    delay();
      return(status);                              // return nRF24L01 status byte
}
/**************************************************
Function: RX_Mode();

Description:
  This function initializes one nRF24L01 device to
  RX Mode, set RX address, writes RX payload width,
  select RF channel, datarate & LNA HCURR.
  After init, CE is toggled high, which means that
  this device is now ready to receive a datapacket. */
/**************************************************/
void RX_Mode(void)
{
  unsigned char tmp;
    nRF24L01_CEL;
    delay();
      tmp = SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // Use the same address on the RX device as the TX device
      tmp = SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // Enable Auto.Ack:Pipe0
      tmp = SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
      tmp = SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
      tmp = SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // Select same RX payload width as TX Payload width
      tmp = SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
      tmp = SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);     // Set PWR_UP bit, enable CRC(2 bytes) & Prim:RX. RX_DR enabled..
      nRF24L01_CEH;
    delay();
    //  This device is now ready to receive one packet of 16 bytes payload from a TX device sending to address
  //  '3443101001', with auto acknowledgment, retransmit count of 10, RF channel 40 and datarate = 2Mbps.

}
/**************************************************/

/**************************************************
Function: TX_Mode();

Description:
  This function initializes one nRF24L01 device to
  TX mode, set TX address, set RX address for auto.ack,
  fill TX payload, select RF channel, datarate & TX pwr.
  PWR_UP is set, CRC(2 bytes) is enabled, & PRIM:TX.

  One high pulse(>10us) on CE will now send this
  packet and expext an acknowledgment from the RX device. */
/**************************************************/
void TX_Mode(void)
{
  unsigned char tmp;
    nRF24L01_CEL;
    delay();
      tmp = SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // Writes TX_Address to nRF24L01
      tmp = SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.Ack
      tmp = SPI_Write_Buf(WR_TX_PLOAD, Buffer, TX_PLOAD_WIDTH); // Writes data to TX payload

      tmp = SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // Enable Auto.Ack:Pipe0
      tmp = SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
      tmp = SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...
      tmp = SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
      tmp = SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
      tmp = SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);     // Set PWR_UP bit, enable CRC(2 bytes) & Prim:TX. MAX_RT & TX_DS enabled..
    nRF24L01_CEH;
    delay();
}
void NRF24L01_init()
{
    //初始化CE、IRQ对应的GPIO
    SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
    PORTB_PCR9=PORT_PCR_MUX(1);
    PORTB_PCR18=PORT_PCR_IRQC(0x0A) | PORT_PCR_MUX(1);
    PORTB_PCR19=PORT_PCR_MUX(1);
    GPIOB_PDDR |= (1<<9) | (1<<19);
    SPI_Init();
    nRF24L01_CEL;
    delay();
    NVICISER2 |= 1<<24;//使能中断NVICISERn=1<<m,其中n=88/32,m=88%32
}
void gpiob_isr(void)
{
    unsigned char tmp;
    tmp=SPI_Read(STATUS);            // read register STATUS's value
    if(tmp&RX_DR)//接收完成中断
        SPI_Read_Buf(RD_RX_PLOAD,Buffer,TX_PLOAD_WIDTH);// read renRF24L01_CEive payload from RX_FIFO buffer
    if(tmp&MAX_RT) //达到最多次重发中断
      SPI_RW_Reg(FLUSH_TX,0);
    tmp = SPI_RW_Reg(WRITE_REG+STATUS,0xff);// clear RX_DR or TX_DS or MAX_RT interrupt flag
    if( (tmp&TX_DS)!=0 )//发送完成中断
    {
        RX_Mode();
    }
    PORTB_ISFR = 1<<18;//清中断
}

//nrf24l01.h

#define nRF24L01_CSNH       (GPIOB_PSOR=1<<9)
#define nRF24L01_CSNL       (GPIOB_PCOR=1<<9)  
#define nRF24L01_CEH        (GPIOB_PSOR=1<<19)   
#define nRF24L01_CEL        (GPIOB_PCOR=1<<19)

//****************************************************************//
// SPI(nRF24L01) commands
#define READ_REG        0x00  // Define read command to register
#define 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
#define MAX_RT      0x10  // Max #of TX retrans interrupt
#define TX_DS       0x20  // TX data sent interrupt
#define RX_DR       0x40  // RX data received
//-----------------------------------------------------------------------------
#define TX_ADR_WIDTH    5   // 5 bytes TX(RX) address width
#define TX_PLOAD_WIDTH  20  // 16 bytes TX payload
extern unsigned char TX_ADDRESS[TX_ADR_WIDTH]; // Define a static TX address
extern unsigned char     Buffer[64];

void SPI_Init(void);
void NRF24L01_init(void);
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes);
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes);
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value);
unsigned char SPI_Read(unsigned char reg);
void clear_buf(unsigned char    *ptr,unsigned char number);
void delay(void);