新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32 驅動無線NRF24L01 完成串口數據傳輸

        STM32 驅動無線NRF24L01 完成串口數據傳輸

        作者: 時間:2016-12-03 來源:網絡 收藏
        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("rn");
        }
        }
        兩個中斷 串口 和 外部中斷
        /*******************************************************************************
        * 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]= 主站蜘蛛池模板: 景谷| 奉新县| 余庆县| 周至县| 洱源县| 西平县| 葫芦岛市| 榆林市| 高邮市| 新化县| 牟定县| 镇赉县| 栾川县| 巴东县| 丰顺县| 务川| 南涧| 沧源| 广河县| 黔东| 师宗县| 凭祥市| 阳信县| 怀远县| 辽阳县| 丰宁| 四川省| 永丰县| 交城县| 韩城市| 云霄县| 岚皋县| 海盐县| 壤塘县| 东乌珠穆沁旗| 赣榆县| 东兴市| 车致| 汾阳市| 渑池县| 安宁市|