赞
踩
STM32F103ZET6的开发板(正点原子战舰和精英板)
nRF24L01(云佳科技)
C与C++混编,c++仅使用了class以及string,比较好恢复为c程序
FreeRTOS
SPI
1.打开软件后,点击File→newSTM32Project
2.选择芯片类型
3.输入项目名、选择为C++目标语言,完成
4.添加头文件路径、源文件路径等
可以直接做第三节的内容,之后再添加头文件路径,源文件路径等,随着工程的增加要随时添加这部分内容
右击工程名,点击最后的属性propertise
后得到如下图
点击Add
增加头文件的路径,没有C++的头文件路径
这里的C++头文件路径可以照着工程中的Includes添加,如下图,把框出的路径添加到头文件路径。
添加的头文件路径会在这个文件夹中显示**(但是不知道为什么上面的几个文件夹的路径虽然创建工程就显示但是还需要挨个手动添加??)**
增加的源文件路径也要添加
采用外部高速晶振和低速外部晶振
debug选用串口线,时基由于使用了FreeRTOS,不建议使用systick
采用STM32的SPI2,全双工主机(master)模式
射频芯片的最高为10MHz,SPI速度设置为以下
根据射频芯片的时序图特征更改CPOL以及CPHA
配置如图
需要增加射频芯片使用的CSN、CE和IRQ引脚,这里要做对应的设置
配置重点是需要重定向printf函数,<stdio.h>中的printf默认是输出到终端,对于嵌入式设备需要对其重定向,此处重定向到串口1
//生成工程后在对应的uart.c文件中加入重定向代码 //代码增加的地方需要在如下类似的两个宏定义之间,否则重新生成代码将覆盖 /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ #include "stdio.h"// #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1, (uint8_t*)&ch,1,HAL_MAX_DELAY); return ch; }
每次修改.ioc文件后都要保存后重新生成代码
/* * nRF24L01.h * * Created on: Mar 28, 2022 * Author: MBW */ #ifndef NRF2401_NRF24L01_H_ #define NRF2401_NRF24L01_H_ #include <stdint.h> #define nRF_ASSERT /* Exported macro ------------------------------------------------------------*/ #ifdef nRF_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr If expr is false, it calls assert_failed function * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * @retval None */ #define nRF_assert(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line); #else #define nRF_assert(expr) ((void)0U) #endif /* USE_FULL_ASSERT */ //use to call C++ function in C file extern "C" void nRF24L01_wrapper(); extern "C" void nRF24L01_receive(); extern "C" void call_onIRQ(); extern "C" void nRF24L01_callRXmode(); namespace nRF { //settings #define nRF_SINGLE_MAXLEN 32 #define ADDRESS_LENGTH 5 #define MAX_TX 0x10 #define TX_OK 0x20 #define RX_OK 0x40 #define TX_ERROR 0x01 #define RX_ERROR 0x02 #define NO_PACKET 0x04 #define NOT_EXIST 0x08 //commands macro #define NRF_READ_REG 0x00 // Define read command to register #define NRF_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 //register address #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 class nRF24L01 final { #define RX_ADDRESS 0 #define TX_ADDRESS 1 public: nRF24L01(); virtual ~nRF24L01(); void onIRQ(); //callback function when enable interrupt uint8_t nRFSendMsg(uint8_t* msg, uint8_t msglen); //send or receive message uint8_t nRFRecvMsg(uint8_t* msg, uint8_t msglen, uint32_t timeout); uint8_t nRFexistDev(); //check if nRF is exist void setEnableCE(void(*func)()); //set GPIO control function void setDisableCE(void(*func)()); void setEnableCSN(void(*func)()); void setDisableCSN(void(*func)()); void setIrq(uint8_t (*func)()); void setAddress(uint8_t txorrx, uint8_t* addr, uint8_t len); void getAddress(uint8_t txorrx, uint8_t* addr, uint8_t len); void setRxMode(); void setTxMode(); private: uint8_t nRFWriteReg(uint8_t reg, uint8_t val); //write or read register uint8_t nRFReadReg(uint8_t reg); uint8_t nRFWriteBuf(uint8_t reg, uint8_t* msg, uint8_t msglen); //send or receive message uint8_t nRFReadBuf(uint8_t reg, uint8_t* msg, uint8_t msglen); //send or receive message void nRFSPIInit(); uint8_t nRFSendPacket(uint8_t* packet, uint8_t len); uint8_t nRFRecvPacket(uint8_t* packet, uint8_t len); void (*enableCE)(); void (*disableCE)(); void (*enableCSN)(); void (*disableCSN)(); uint8_t (*getIRQ)(); uint8_t rx_address[5]; uint8_t tx_address[5]; }; extern nRF24L01* g_nrf; } /* namespace nRF */ #endif /* NRF2401_NRF24L01_H_ */
/* * nRF24L01.h * * Created on: Mar 28, 2022 * Author: MBW */ #ifndef NRF2401_NRF24L01_H_ #define NRF2401_NRF24L01_H_ #include <stdint.h> #define nRF_ASSERT /* Exported macro ------------------------------------------------------------*/ #ifdef nRF_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr If expr is false, it calls assert_failed function * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * @retval None */ #define nRF_assert(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line); #else #define nRF_assert(expr) ((void)0U) #endif /* USE_FULL_ASSERT */ //use to call C++ function in C file extern "C" void nRF24L01_wrapper(); extern "C" void nRF24L01_receive(); extern "C" void call_onIRQ(); extern "C" void nRF24L01_callRXmode(); namespace nRF { //settings #define nRF_SINGLE_MAXLEN 32 #define ADDRESS_LENGTH 5 #define MAX_TX 0x10 #define TX_OK 0x20 #define RX_OK 0x40 #define TX_ERROR 0x01 #define RX_ERROR 0x02 #define NO_PACKET 0x04 #define NOT_EXIST 0x08 //commands macro #define NRF_READ_REG 0x00 // Define read command to register #define NRF_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 //register address #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 class nRF24L01 final { #define RX_ADDRESS 0 #define TX_ADDRESS 1 public: nRF24L01(); virtual ~nRF24L01(); void onIRQ(); //callback function when enable interrupt uint8_t nRFSendMsg(uint8_t* msg, uint8_t msglen); //send or receive message uint8_t nRFRecvMsg(uint8_t* msg, uint8_t msglen, uint32_t timeout); uint8_t nRFexistDev(); //check if nRF is exist void setEnableCE(void(*func)()); //set GPIO control function void setDisableCE(void(*func)()); void setEnableCSN(void(*func)()); void setDisableCSN(void(*func)()); void setIrq(uint8_t (*func)()); void setAddress(uint8_t txorrx, uint8_t* addr, uint8_t len); void getAddress(uint8_t txorrx, uint8_t* addr, uint8_t len); void setRxMode(); void setTxMode(); private: uint8_t nRFWriteReg(uint8_t reg, uint8_t val); //write or read register uint8_t nRFReadReg(uint8_t reg); uint8_t nRFWriteBuf(uint8_t reg, uint8_t* msg, uint8_t msglen); //send or receive message uint8_t nRFReadBuf(uint8_t reg, uint8_t* msg, uint8_t msglen); //send or receive message void nRFSPIInit(); uint8_t nRFSendPacket(uint8_t* packet, uint8_t len); uint8_t nRFRecvPacket(uint8_t* packet, uint8_t len); void (*enableCE)(); void (*disableCE)(); void (*enableCSN)(); void (*disableCSN)(); uint8_t (*getIRQ)(); uint8_t rx_address[5]; uint8_t tx_address[5]; }; extern nRF24L01* g_nrf; } /* namespace nRF */ #endif /* NRF2401_NRF24L01_H_ */
/* * nRF24L01.cpp * * Created on: Mar 28, 2022 * Author: MBW */ #include <nRF24L01.h> #include "spi.h" #include "gpio.h" #include <string> #include <stdio.h> namespace nRF { nRF24L01* g_nrf = nullptr; //global nrf pointer nRF24L01::nRF24L01() { tx_address[0] = 0xE1; //default address when user not set address tx_address[1] = 0xE2; tx_address[2] = 0xE3; tx_address[3] = 0xE4; tx_address[4] = 0xE5; rx_address[0] = 0xE1; rx_address[1] = 0xE2; rx_address[2] = 0xE3; rx_address[3] = 0xE4; rx_address[4] = 0xE5; nRFSPIInit(); //special setting for nRF24L01 device about spi } nRF24L01::~nRF24L01() { //do nothing } void nRF24L01::setAddress(uint8_t txorrx, uint8_t* addr, uint8_t len) { nRF_assert(len >= ADDRESS_LENGTH + 1); // limit len <= 5 if (txorrx == TX_ADDRESS) { tx_address[0] = addr[0]; tx_address[1] = addr[1]; tx_address[2] = addr[2]; tx_address[3] = addr[3]; tx_address[4] = addr[4]; } else { rx_address[0] = addr[0]; rx_address[1] = addr[1]; rx_address[2] = addr[2]; rx_address[3] = addr[3]; rx_address[4] = addr[4]; } } void nRF24L01::getAddress(uint8_t txorrx, uint8_t* addr, uint8_t len) { nRF_assert(len >= ADDRESS_LENGTH + 1); if (txorrx == TX_ADDRESS) { addr[0] = tx_address[0]; addr[1] = tx_address[1]; addr[2] = tx_address[2]; addr[3] = tx_address[3]; addr[4] = tx_address[4]; addr[5] = 0; } else { addr[0] = rx_address[0]; addr[1] = rx_address[1]; addr[2] = rx_address[2]; addr[3] = rx_address[3]; addr[4] = rx_address[4]; addr[5] = 0; } } void nRF24L01::setRxMode() { disableCE(); //power down state or standby state to configure nRF24L01 nRFWriteBuf(NRF_WRITE_REG + RX_ADDR_P0, rx_address, ADDRESS_LENGTH); nRFWriteReg(NRF_WRITE_REG + EN_AA, 0x01); nRFWriteReg(NRF_WRITE_REG + EN_RXADDR, 0x01); nRFWriteReg(NRF_WRITE_REG + RF_CH, 40); nRFWriteReg(NRF_WRITE_REG + RX_PW_P0, nRF_SINGLE_MAXLEN); nRFWriteReg(NRF_WRITE_REG + RF_SETUP, 0x0F); nRFWriteReg(NRF_WRITE_REG + CONFIG, 0x0F); nRFWriteReg(FLUSH_TX, 0XAA); nRFWriteReg(FLUSH_RX, 0XAA); enableCE(); HAL_Delay(1); } void nRF24L01::setTxMode() { disableCE(); //configure nRFWriteBuf(NRF_WRITE_REG + TX_ADDR, tx_address, ADDRESS_LENGTH); nRFWriteBuf(NRF_WRITE_REG + RX_ADDR_P0, rx_address, ADDRESS_LENGTH); nRFWriteReg(NRF_WRITE_REG + EN_AA, 0x01); nRFWriteReg(NRF_WRITE_REG + EN_RXADDR, 0x01); nRFWriteReg(NRF_WRITE_REG + SETUP_RETR, 0x1a); nRFWriteReg(NRF_WRITE_REG + RF_CH, 40); nRFWriteReg(NRF_WRITE_REG + RF_SETUP, 0x0F); nRFWriteReg(NRF_WRITE_REG + CONFIG, 0x0E); nRFWriteReg(FLUSH_TX, 0XAA); nRFWriteReg(FLUSH_RX, 0XAA); enableCE(); HAL_Delay(1); } //when interrupt happen, call this function void nRF24L01::onIRQ() { uint8_t msg[33] = {0}; nRF::g_nrf->nRFRecvMsg(msg, 32 , 60*1000); msg[32] = 0; printf("irq get msg: %s\r\n", msg); } //wrapper C++ function for using in C file extern "C" void call_onIRQ() { nRF::g_nrf->onIRQ(); } //set irq GPIO void nRF24L01::setIrq(uint8_t (*func)()) { getIRQ = func; } //send msg longer than 32 bytes uint8_t nRF24L01::nRFSendMsg(uint8_t* msg, uint8_t msglen) { uint8_t packetnum = msglen / nRF_SINGLE_MAXLEN; uint8_t txresult; for (int i = 0; i < packetnum; i++) { txresult = nRFSendPacket(msg + i * nRF_SINGLE_MAXLEN, nRF_SINGLE_MAXLEN); if (txresult != TX_OK) return txresult; } if (msglen % nRF_SINGLE_MAXLEN) { txresult = nRFSendPacket(msg + packetnum * nRF_SINGLE_MAXLEN, nRF_SINGLE_MAXLEN); if (txresult != TX_OK) return txresult; } return SUCCESS; } //send a packet less than 32 bytes uint8_t nRF24L01::nRFSendPacket(uint8_t* packet, uint8_t len) { disableCE(); nRFWriteBuf(WR_TX_PLOAD , packet, len); //actually , len must be 32 if send packet nRFWriteReg(NRF_WRITE_REG + CONFIG, 0x0E); //set to txmode enableCE(); //enable TX HAL_Delay(1); while(getIRQ() != DISABLE); //wait for TX_OK or MAX_TX disableCE(); HAL_Delay(1); uint8_t status = nRFReadReg(NRF_READ_REG + STATUS); //get STATUS nRFWriteReg(NRF_WRITE_REG + STATUS, status); //clear interrupt nRFWriteReg(FLUSH_TX, 0xff); //clear TX FIFO if (status & MAX_TX) { return MAX_TX; } if (status & TX_OK) { return TX_OK; } return TX_ERROR; } uint8_t nRF24L01::nRFRecvPacket(uint8_t* packet, uint8_t len) { uint8_t status = nRFReadReg(NRF_READ_REG + STATUS); nRFWriteReg(NRF_WRITE_REG + STATUS, status); //clear interrupt //auto clear FIFO after read RX FIFO if (status & RX_OK) { nRFReadBuf(RD_RX_PLOAD, packet, len); return SUCCESS; } return NO_PACKET; } //receive the designated length msg in timeout uint8_t nRF24L01::nRFRecvMsg(uint8_t* msg, uint8_t msglen, uint32_t timeout) { uint8_t packetnum = msglen / nRF_SINGLE_MAXLEN; uint8_t cnt = 0; uint32_t tickstart = HAL_GetTick(); while (HAL_GetTick()-tickstart < timeout) { if (cnt < packetnum) { int ret = nRFRecvPacket(msg + cnt * nRF_SINGLE_MAXLEN, nRF_SINGLE_MAXLEN); if (ret == SUCCESS) cnt++; } else { if (msglen % nRF_SINGLE_MAXLEN == 0) return SUCCESS; int ret = nRFRecvPacket(msg + packetnum * nRF_SINGLE_MAXLEN, msglen % nRF_SINGLE_MAXLEN); if (ret == SUCCESS) return SUCCESS; } } return RX_ERROR; } uint8_t nRF24L01::nRFWriteBuf(uint8_t reg, uint8_t* msg, uint8_t msglen) { uint8_t status; uint8_t nouse; nRF_assert(msglen <= nRF_SINGLE_MAXLEN); disableCSN(); HAL_SPI_TransmitReceive(&hspi2, ®, &status,1, 10); for (int i = 0; i < msglen; i++) HAL_SPI_TransmitReceive(&hspi2, msg+i, &nouse , 1, 10); enableCSN(); return status; } uint8_t nRF24L01::nRFReadBuf(uint8_t reg, uint8_t* msg, uint8_t msglen) { uint8_t status; uint8_t nouse; nRF_assert(msglen <= nRF_SINGLE_MAXLEN); disableCSN(); HAL_SPI_TransmitReceive(&hspi2, ®, &status, 1, 10); for (int i = 0; i < msglen; i++) HAL_SPI_TransmitReceive(&hspi2, &nouse, msg+i, 1, 10); enableCSN(); return status; } uint8_t nRF24L01::nRFWriteReg(uint8_t reg, uint8_t val) { uint8_t status; uint8_t nouse; disableCSN(); HAL_SPI_TransmitReceive(&hspi2, ®, &status, 1, 10); HAL_SPI_TransmitReceive(&hspi2, &val, &nouse, 1, 10); enableCSN(); return status; } uint8_t nRF24L01::nRFReadReg(uint8_t reg) { uint8_t regval; uint8_t nouse; disableCSN(); HAL_SPI_TransmitReceive(&hspi2, ®, &nouse, 1, 10); HAL_SPI_TransmitReceive(&hspi2, &nouse, ®val, 1, 10); enableCSN(); return regval; } //check if connect the device uint8_t nRF24L01::nRFexist() { uint8_t buf[5] = {0,0,0,0,0}; disableCE(); nRFWriteBuf(NRF_WRITE_REG+TX_ADDR, tx_address, ADDRESS_LENGTH); nRFReadBuf(NRF_READ_REG+TX_ADDR, buf, ADDRESS_LENGTH); for (int i = 0; i < ADDRESS_LENGTH; i++) { if (buf[i] != tx_address[i]) return NOT_EXIST; } return SUCCESS; } //special for SPI setting void nRF24L01::nRFSPIInit() { __HAL_SPI_DISABLE(&hspi2); hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; HAL_SPI_Init(&hspi2); __HAL_SPI_ENABLE(&hspi2); } void nRF24L01::setEnableCE(void(*func)()) { enableCE = func; } void nRF24L01::setDisableCE(void(*func)()) { disableCE = func; disableCE(); } void nRF24L01::setEnableCSN(void(*func)()) { enableCSN = func; enableCSN(); } void nRF24L01::setDisableCSN(void(*func)()) { disableCSN = func; } } /* namespace nRF */
//用于C文件调用C++,作为对应C++代码的wrapper //函数前需要加上 extern "C" ,表示按照C方式编译 //可新建位置或者放在源文件中 extern "C" void nRF24L01_callSend() { std::string msg = "hello nrf24 hello nrf24 hello nrf24 hello nrf24"; printf("send msg begin\r\n"); nRF::nRF24L01 nrf1; nrf1.setEnableCE(setCE); nrf1.setDisableCE(resetCE); nrf1.setEnableCSN(setCSN); nrf1.setDisableCSN(resetCSN); nrf1.setIrq(getIrq); HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); if (nrf1.nRFexistDev() == 0) { nrf1.setTxMode(); uint8_t ret = nrf1.nRFSendMsg((uint8_t*)msg.c_str(), msg.length()); if (ret == SUCCESS) printf("send result = %d\r\n", ret); else { printf("send failed [errorcode:0X%X]\r\n", ret); } } else { printf("no device!\r\n"); } printf("send msg end\r\n"); } extern "C" void nRF24L01_callRXmode() { nRF::g_nrf = new nRF::nRF24L01; nRF::g_nrf->setEnableCE(setCE); nRF::g_nrf->setDisableCE(resetCE); nRF::g_nrf->setEnableCSN(setCSN); nRF::g_nrf->setDisableCSN(resetCSN); printf("rx mode wait interrupt\r\n"); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); nRF::g_nrf->setRxMode(); } extern "C" void nRF24L01_receiveTimout() { uint8_t msg[50] = {0}; nRF::nRF24L01 nrf1; nrf1.setEnableCE(setCE); nrf1.setDisableCE(resetCE); nrf1.setEnableCSN(setCSN); nrf1.setDisableCSN(resetCSN); nrf1.setIrq(getIrq); printf("waiting msg...\r\n"); nrf1.setRxMode(); nrf1.nRFRecvMsg(msg, 32 , 60*1000); //waiting 60s printf("msg : %s\r\n", msg); } //wrapper C++ function for using in C file extern "C" void call_onIRQ() { nRF::g_nrf->onIRQ(); }
生成的main.c文件要更名为main.cpp (每次更改ioc重新生成代码之前先改回main.c,生成后再改为main.cpp,如果不改,则会另外生成一个main.c)
main.c改为main.cpp 后要把 void MX_FREERTOS_Init(void)
前加上 extern "C"
,因为这个函数本身是freertos.c文件中定义的,main.c更名为main.cpp找不到对应的符号,因为C和C++编译为不同的符号
无论发送还是接收都要进行如下的函数的处理,即绑定使用的引脚对应的GPIO
nRF::g_nrf->setEnableCE(setCE);
nRF::g_nrf->setDisableCE(resetCE);
nRF::g_nrf->setEnableCSN(setCSN);
nRF::g_nrf->setDisableCSN(resetCSN);
//gpio.c中设置了这几个函数,也可以直接传入HAL_GPIO_WritePIN()
void setCE() {HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, GPIO_PIN_SET);}
void resetCE() {HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, GPIO_PIN_RESET);}
void setCSN() {HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_SET);}
void resetCSN() {HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_RESET);}
uint8_t getIrq() { return HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6);}
3. C和C++混合编程,采用的FreeRTOS创建任务,可以在对应的任务中增加Cwrapper后的代码
作为发送:
可以开辟一个缓冲区,用于填入发送的数据,然后调用nRF24L01_callSend
函数,进行发送。
作为接收:
nRF24L01_receiveTimout
这个可以设置为在一定时间内接收一定大小的数据
或者采用中断的方式,收到数据后存储到指定的缓冲区,收集一定的数据后进行数据的处理
中断函数尽量处理不高耗时的任务,中断可只做数据接收后放到指定的开辟的缓冲区
处理缓冲区的工作在工作线程中执行,中断只负责转移数据
不能够正确的写入到nRF24L01的寄存器,或者部分写入
读取数据超时
每次读取的错误数据是相同的,问题可复现
//第一块模块 //STM32CUBEIde读出的内容 send msg begin txbuf : 0xE5 0xB5 0xE2 0xA0 0xB2 rxbuf : 0xE5 0xB5 0xE2 0xA0 0xB2 enaa :0x7 enrxaddr :0x7 setup :0x46 rfch :0x88 rfsetup :0x1 config = 0x2A status = 0xE send msg end //正点原子代码读出的寄存器内容 txbuf : 0xb2 0xe5 0xb5 0xe2 0xa0 //0xb2数据位置错了,其他没问题 rxbuf : 0xb2 0xe5 0xb5 0xe2 0xa0 EN_AA = 7 EN_RXADDR = 7 SETUP RETRY = 46 RF_CH = 88 RF_SETUP = F //不同 CONFIG = 2A STAUTS = E //第二块模块 //STM32CUBEIde读出的内容 send msg begin txbuf : 0xE7 0xE7 0xE7 0xE7 0xE7 rxbuf : 0xE7 0xE7 0xE7 0xE7 0xE7 enaa :0x3F enrxaddr :0x3 setup :0x3 rfch :0x2 rfsetup :0x0 config = 0x8 status = 0xE send msg end //正点原子代码读出的寄存器内容 txbuf : 0xe7 0xe7 0xe7 0xe7 0xe7 //不具代表性 rxbuf : 0xe7 0xe7 0xe7 0xe7 0xe7 EN_AA = 3F EN_RXADDR = 3 SETUP RETRY = 3 RF_CH = 2 RF_SETUP = F //不同 CONFIG = 8 STAUTS = E //第二块第第二次测试 //STM32CUBEIde读出的内容 send msg begin txbuf : 0x43 0x10 0x10 0x1 0x34 rxbuf : 0x43 0x10 0x10 0x1 0x34 enaa :0x1 enrxaddr :0x1 setup :0x1A rfch :0x40 rfsetup :0x0 config = 0xE status = 0xE send msg end //正点原子代码读出的寄存器内容 txbuf : 0x34 0x43 0x10 0x10 0x1 //有区别 rxbuf : 0x34 0x43 0x10 0x10 0x1 EN_AA = 1 EN_RXADDR = 1 SETUP RETRY = 1A RF_CH = 40 RF_SETUP = F //不同 CONFIG = E STAUTS = E
更改了disable CRC
项目中更改了HAL_SPI_Transmit
为 HAL_SPI_TransmitReceive
,可能是由于前者仅发送处理接收区,导致SPI同步收到的数据未被清除(仅猜测)
硬件错误,按下按键后发送第一次之后即发生Hard_Fault
增加线程栈空间为512
接收不到数据,发送端表示已经重发引起中断
经过测试发现,每次写给TX_FIFO必须写入32字节,否则nRF24L0不会发送!!
每次进入发送或者接收状态要清除缓冲区,防止错误导致缓冲区存在数据
没事干的话改成纯c吧,C++没啥必要哈哈哈
STM32—cubeMX+HAL库的SPI接口使用_夜风~的博客-CSDN博客_cubemx spi
正点原子库函数手册
nRF24L01的手册
STM32CubeIDE使用技巧(FreeRTOS点亮一盏灯)_重拾十年梦的博客-CSDN博客_cubeide自动补全
STM32L051C8T6 HAL库 + nRF24L01 收发案例(硬件SPI通讯)_Ch_champion的博客-CSDN博客_hal spi实例
使用STM32CubeMX开发三:按键中断实验 - 无网不进 - 博客园 (cnblogs.com)
attribute((weak)) 简介及作用_侵蚀昨天的博客-CSDN博客___attribute__((weak))
使用stm32cubeIDE git代码(gitee)_violet1714的博客-CSDN博客
stm32 FreeRTOS 某个任务一直不被运行_zhuimeng_ruili的博客-CSDN博客_freertos任务不运行
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。