RISC-V MCU開(kāi)發(fā)實(shí)例(二):搭配Si24R1 通信模式進(jìn)行調試

發(fā)布時(shí)間:2022-8-9 15:51    發(fā)布者:郭13824368625
關(guān)鍵詞: RISC-V , MCU , SI24R1 , 單片機
目的
通過(guò)CSM32RV20開(kāi)發(fā)平臺,使用硬件SPI接口與Si24R1進(jìn)行通信,通信成功后,通過(guò)串口打印數據。

實(shí)現過(guò)程:
1.中斷向量表和系統時(shí)鐘初始化
在IDE里新建項目后,都會(huì )包含CLIC_Init()和System_Clock_Init()兩個(gè)函數。中斷向量表初始化,系統中斷初始化,用戶(hù)無(wú)需關(guān)心。系統時(shí)鐘初始化函數中,可以方便的選中時(shí)鐘源、時(shí)鐘分頻系數、外設時(shí)鐘使能和RC頻率選擇。
int main(void){    ///----System Init ---------------------------------------------------------------------------------------------    CLIC_Init();//中斷向量表初始化    System_Clock_Init();//系統時(shí)鐘初始化void System_Clock_Init(void)//系統時(shí)鐘初始化{    //時(shí)鐘源開(kāi)關(guān)    CMU->SRC_EN  = 1<<1   //RCOSC    bit[1]:0-off, 1-on                  |1<<0;  //crystal  bit[0]:0-off, 1-on    //外設和內核時(shí)鐘來(lái)源選擇        CMU->CLK_SEL = 1<<2   //phripheral  bit[3:2]:0-RCOSC, 1-crystal, 2-LSI(3K), 3-reserved                  |1<<0;  //cpu         bit[1:0]:0-RCOSC, 1-crystal, 2-LSI(3K), 3-reserved    //設置時(shí)鐘分頻系數    CMU->CLK_DIV = 0<<10  //RTC         bit[14:10]:0-2, 1-2, 2-2, 3-2, 4-4, 5-4, 6-6, 7-6 ......                  |0<<5   //phripheral  bit[9:5]:0-1, 1-1, 2-2, 3-3, 4-4, 5-5,......31-31                  |0<<0;  //CPU         bit[9:5]:0-1, 1-1, 2-2, 3-3, 4-4, 5-5,......31-31    //外設時(shí)鐘使能    CMU->PER_EN  = 1;    //bit[0]:0-off, 1-on    //RC頻率選擇    CMU_RC_DEFAULT->RC_DEFAULT = 0; //bit[0]:0-16MHz, 1-32MHz}

2.外設初始化
2.1外設初始化(串口)
串口初始化:選中UART1,UART1即可以用作燒錄使用(開(kāi)發(fā)板串口默認使用UART1),又可以調用打印,方便數據輸出。UART1:PA6:TX1,復用配置AF0(默認)。PA5:RX1,復用配置AF0(默認)。
UART_Init_case1(UART1);   //串口初始化
由于開(kāi)發(fā)板上使用的晶振為32MHz,那么我們設置0x0116<<8串口波特率就是115200
UARTx->CTRL = 0<<25        //接收中斷使能: 0-off,1-on                 |0<<24        //發(fā)送中斷使能:0-off,1-on                 |0x0116<<8    //波特率(對應16M時(shí)鐘):                               //0x1a0b-2400,0x0683-9600,0x0341-19200,0x0116-57600,0x008b-115200                               //0x0045-230400,0x0023-460800,0x0011-921600,0x000d-1128800                 |1<<6         //模式選擇:0-模式0,1-模式1,2/3-模式2                 |0<<5         //多處理器使能                 |1<<4         //接收使能                 |0<<3         //發(fā)送數據bit8                 |0<<2;        //接收數據bit8


2.2外設初始化(SPI)
SPI初始化,選中非中斷模式。Si24R1采用四線(xiàn)制SPI,與MCU連接共6根線(xiàn)。Si24R1芯片引腳介紹(MOSI和MISO直接與MCU的硬件SPI對應連接即可,即MOSI與SPI1_MOSI連接)。CE,芯片開(kāi)啟信號,激活 RX 或 TX 模式。CSN,SPI 片選信號。SCK,SPI 時(shí)鐘信號。MOSI,SPI 輸入信號。MISO,SPI輸出信號。IRQ,可屏蔽中斷信號(可以通過(guò)0x00寄存器CONFIG配置屏蔽),低電平有效。

SPI_Init_case1(SPI1);     //SPI初始化,非中斷模式
CSM32RV20,硬件SPI1引腳說(shuō)明:PA2-SPI1_SCK,PA3-SPI1_MISO,PA4_SPI1_MOSI.
  if(SPIx==SPI1)    {        //用戶(hù)自選CSN,軟件操作片選信號        //配置SCK        GPIO_MODE_Init(GPIOA, PIN2, GPIO_MODE_AF);  //PA2復用模式        GPIO_AF_Init(GPIOA,  PIN2,  GPIO_AF0);  //PA2復用到SPI1_SCK        //配置MISO        GPIO_MODE_Init(GPIOA, PIN3, GPIO_MODE_AF);  //PA3復用模式        GPIO_AF_Init(GPIOA,  PIN3,  GPIO_AF0);  //PA3復用到SPI1_MISO        //配置MOSI        GPIO_MODE_Init(GPIOA, PIN4, GPIO_MODE_AF);  //PA4復用模式        GPIO_AF_Init(GPIOA,  PIN4,  GPIO_AF0);  //PA4復用到SPI1_MOSI    }
根據Si24R1的SPI協(xié)議,CPHA時(shí)鐘相位和CPOL的時(shí)鐘極性(SCK空閑時(shí)狀態(tài)為低電平,上升沿采樣下降沿輸出),選中SPI模式0。SPI速率選擇為8分頻-4MHz。使用軟件CSN控制
SPIx->CTRL = 0x0<<8     //中斷使能:0-關(guān)閉,1-開(kāi)啟                |0x0<<7     //時(shí)鐘極性:0-低電平,1-高電平                |0x0<<6     //時(shí)鐘相位:0-前沿采樣,后沿輸出,1-前沿輸出,后沿采樣,                |0x1<<4     //SPI使能:0-關(guān)閉,1-使能                |0x3;       //時(shí)鐘分頻:0-2分頻,1-2分頻,2-2分頻,3-8分頻,4-16分頻,5-32分頻,6-64分頻,其他:64分頻

2.3外設初始化(GPIO)
初始化CE,CSN,IRQ
SPI1_CSN_Init_case1();//CFG: CE-GPIO9,CSN-GPIO8,IRQ-GPIO7void SPI1_CSN_Init_case1(void)//CFG: CE-GPIO9,CSN-GPIO8,IRQ-GPIO7{   GPIO_MODE_Init(GPIOA,PIN8,GPIO_MODE_OUTPUT);//CSN    GPIO_Write(GPIOA,PIN8,GPIO_SET);//CSN=1    GPIO_MODE_Init(GPIOA,PIN9,GPIO_MODE_OUTPUT);//CE    GPIO_Write(GPIOA,PIN9,GPIO_RESET);//CE=0    GPIO_MODE_Init(GPIOA,PIN7,GPIO_MODE_INPUT);//IRQ}

2.4外設初始化(中斷)
中斷IRQ引腳,開(kāi)發(fā)板上選擇為PA7。
  GPIO_EXIT_Init_case4(GPIOA, PIN7);//檢測下降沿   Interrupt_Enable(EXIT9_5_int_ID);//CLIC使能EXIT中斷   SYS_Interrupt_Enable(); CLIC開(kāi)總中斷void GPIO_EXIT_Init_case4(GPIO_TypeDef *GPIOx, uint8_t PINx)//檢測下降沿{    GPIO_MODE_Init(GPIOx, PINx, GPIO_MODE_INPUT);    GPIO_EXIT_MODE_Init(GPIOx, PINx, GPIO_EXIT_FALLING);    GPIO_PULL_Init(GPIOx, PINx, GPIO_PULLUP);  //內部上拉    GPIO_INTER_enable(GPIOx, PINx);   //GPIO 中斷使能}
中斷處理函數:
void EXIT9_5_IRQHandler(void){    if(EXTI->ISR&(0x1<<7)) //外部中斷 PA7    {        IRQ_flag=1;        EXTI->ISR |= 0x1<<7;        //IRQ Handler......    }

3.Si24R1通信模式介紹
Si24R1通信模式有兩種,一種是Si24R1通信模式,一種是兼容模式,兩者的區別就在于是否有包控制字,包控制可以實(shí)現動(dòng)態(tài)負載長(cháng)度,ACK通信,ACKPAYLAOD通信等。

Si24R1通信模式:

兼容模式:



4.Si24R1模塊

5. SPI函數
SPI讀寫(xiě)函數:SPI1讀寫(xiě)一個(gè)字節
uint8_t spi_rw_byte(uint8_t byte){    uint8_t a;    SPI_Transceive(SPI1,&byte,&a,1);    return  a;}
SPI寫(xiě)寄存器:寫(xiě)數據value到reg寄存器,同時(shí)返回寄存器值
uint8_t spi_rw_reg(uint8_t reg,uint8_t value)        {                uint8_t status;                reg |= W_REGISTER ;                        //寫(xiě)寄存器命令        GPIO_Write(GPIOA,PIN8,GPIO_RESET);                status=spi_rw_byte(reg);                    //選擇寄存器,同時(shí)返回狀態(tài)字                spi_rw_byte(value);        GPIO_Write(GPIOA,PIN8,GPIO_SET);                return status;                //返回狀態(tài)寄存器        }
SPI讀寄存器:
//========從reg寄存器中讀一個(gè)字節的數據========uint8_t spi_rd_reg(uint8_t reg){        uint8_t value;        reg |= R_REGISTER ;       //讀寄存器命令        GPIO_Write(GPIOA,PIN8,GPIO_RESET);    spi_rw_byte(reg);        value = spi_rw_byte(0);         //從該寄存器中讀數據    GPIO_Write(GPIOA,PIN8,GPIO_SET);        return (value );                     //返回狀態(tài)寄存器}
SPI讀BUFF:
//函數:spi_read_buf()//功能:從reg寄存器讀出bytes個(gè)字節,通常用來(lái)讀取接收通道數據 或 接收/發(fā)送地址//=====================================================================================uint8_t spi_read_buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes){                uint8_t status;                uint8_t i;                reg |= R_REGISTER;    GPIO_Write(GPIOA,PIN8,GPIO_RESET);          status  = spi_rw_byte(reg);                      // 選擇寄存器,同時(shí)返回狀態(tài)字          for(i = 0; i < bytes; i++)    {                   pBuf = spi_rw_byte(0);    // 逐個(gè)字節從Si24R1讀出        }          GPIO_Write(GPIOA,PIN8,GPIO_SET);                             // CSN拉高,結束數據傳輸          return(status);                                   // 返回狀態(tài)寄存器}
SPI寫(xiě)BUFF:
//函數:spi_write_buf()//功能:把pBuf緩存中的數據寫(xiě)入到Si24R1,通常用來(lái)寫(xiě)入發(fā)射通道數據 或 接收/發(fā)送地址//=====================================================================================uint8_t spi_write_buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes){                uint8_t status, i;                reg |= W_REGISTER;          GPIO_Write(GPIOA,PIN8,GPIO_RESET);                            // CSN置低,開(kāi)始傳輸數據          status         = spi_rw_byte(reg);      // 選擇寄存器,同時(shí)返回狀態(tài)字          for(i = 0; i < bytes; i++)    {                   spi_rw_byte(pBuf);        // 逐個(gè)字節寫(xiě)入Si24R1        }          GPIO_Write(GPIOA,PIN8,GPIO_SET);       // CSN拉高,結束數據傳輸          return(status);                      // 返回狀態(tài)寄存器}

6.TX_mode和RX_mode配置
TX_mode: CE拉低后,配置發(fā)射地址、發(fā)射地址寬度、射頻信道、傳輸速率,發(fā)射功率,配置發(fā)射模式、CRC、清除STATUS寄存器的標志位。。。ǹ赡茉谡{試程序或者異常退出,沒(méi)有清除STATUS,但是芯片沒(méi)斷電,可能IRQ的電平一直為低,最好就在初始化時(shí)清除STATUS寄存器的標志位。
spi_rw_reg(STATUS,0xff);//Si24R1 NOACK 發(fā)射模式void Si24R1_Tx_Mode(void){        GPIO_Write(GPIOA,CE_Pin,GPIO_RESET);    spi_write_buf(TX_ADDR, TX_ADDRESS, 5); // 寫(xiě)入發(fā)送地址        spi_rw_reg(FEATURE, 0x01); // 使能 W_TX_PAYLOAD_NOACK 命令        spi_rw_reg(SETUP_AW, 0x03); // 5 byte Address width        spi_rw_reg(RF_CH, 2); // 選擇射頻通道0x40        spi_rw_reg(RF_SETUP, 0x0f); // 數據傳輸率 2Mbps        spi_rw_reg(CONFIG, 0x0e); //配置為發(fā)射模式、CRC 為 2Bytes    spi_rw_reg(STATUS,0xff);        //GPIO_Write(GPIOA,CE_Pin,GPIO_SET);}
RX_mode: 發(fā)射端的配置與接收端的配置一致即可
//Si24R1 NOACK 接收模式void Si24R1_Rx_Mode(void){        GPIO_Write(GPIOA,CE_Pin,GPIO_RESET);        spi_write_buf(RX_ADDR_P0, TX_ADDRESS, 5); // 寫(xiě)入接收地址//        spi_rw_reg(FEATURE, 0x01); // 使能 W_TX_PAYLOAD_NOACK 命令        spi_rw_reg(EN_RXADDR , 0x01); // 使能接收通道        spi_rw_reg(RF_CH, 2); // 選擇射頻通道0x40        spi_rw_reg(RX_PW_P0 ,TX_PLOAD_WIDTH ); // 設置接收通道0負載數據寬度        spi_rw_reg(SETUP_AW, 0x03);                                                                   // 5 byte Address width        spi_rw_reg(RF_SETUP, 0x0f); // 數據傳輸率 2Mbps        spi_rw_reg(CONFIG, 0x0f); //配置為接收方、RC 為 2Bytes        spi_rw_reg(STATUS,0xff);////        GPIO_Write(GPIOa,CE_Pin,GPIO_SET);}
Si24R1_TxPacket():發(fā)射函數,主要是給TX_FIFO填充數據,CE拉高后就會(huì )發(fā)射出去。其中要注意:發(fā)射前最好擦除FIFO,再填寫(xiě)FIFO,這樣對異常的數據發(fā)送可以起到一定的屏蔽作用,否則可能會(huì )陷入始終發(fā)上一包寫(xiě)入數據的怪圈。等到IRQ下降沿中斷后,判斷是否為發(fā)射完成中斷,完成即返回TX_OK;
uint8_t Si24R1_TxPacket(){        uint8_t sta;        uint8_t TX_BUF[TX_PLOAD_WIDTH] = {0,7,7,5,8,5,2,1};        IRQ_flag=0;    spi_rw_reg(FLUSH_TX,0xff);    spi_rw_reg(FLUSH_RX,0xff);        //GPIO_Write(GPIOA,CE_Pin,GPIO_RESET);        //使用NOACK模式時(shí),應使用命令 W_TX_PAYLOAD_NOACK        spi_write_buf(W_TX_PAYLOAD_NOACK,TX_BUF,TX_PLOAD_WIDTH);//寫(xiě)數據到TX BUF  //        spi_write_buf(W_TX_PAYLOAD,TX_BUF,TX_PLOAD_WIDTH);//寫(xiě)數據到TX BUF         GPIO_Write(GPIOA,CE_Pin,GPIO_SET);//啟動(dòng)發(fā)送         Delay32M_us(10);        while(0==IRQ_flag)        {        NOP;     //切記一定得加NOP指令,由于GCC編譯器優(yōu)化問(wèn)題,程序會(huì )只調用一次中斷標志。        }//等待發(fā)送完成        IRQ_flag=0;        sta = spi_rd_reg(STATUS);        // 返回狀態(tài)寄存器        spi_rw_reg(W_REGISTER+STATUS,sta); //清除TX_DS或MAX_RT中斷標志        if(sta&MAX_RT)//達到最大重發(fā)次數        {                spi_rw_reg(FLUSH_TX,0xff);//清除TX FIFO寄存器                return MAX_RT;        }        if(sta&TX_OK)//發(fā)送完成        {                return TX_OK;        }        return 0xff;//其他原因發(fā)送失敗}
其中,需要注意的是:在等待中斷的標志IRQ_flag時(shí),如果直接判斷,由于GCC編譯器優(yōu)化,我們利用IDE的反匯編功能,查看下兩者的區別:


while(0==IRQ_flag);


while(0==IRQ_flag)        {        NOP;            }
7.通信判斷
main()函數中,調用Si24R1_TxPacket();函數,判斷返回值是否為發(fā)射完成TX_OK標志,閃燈+打印即可。打印這里,雖然庫函數里有printf()和ee_printf(),都支持,但是推薦使用ee_printf()函數,這個(gè)是簡(jiǎn)化版的printf函數(而不是C運行庫中提供的printf函數),以此生成的代碼體積就會(huì )更小。
      sta=Si24R1_TxPacket( );        Delay32M_ms(500);        if(sta==TX_OK)        {        GPIO_Write(GPIOA,PIN10,GPIO_RESET);        Delay32M_ms(500);        GPIO_Write(GPIOA,PIN10,GPIO_SET);        ee_printf("Hello,IC農民\r\n");        }        else            Delay32M_ms(20);        }


總結
1.注意在等中斷IRQ產(chǎn)生后的IRQ_flag時(shí),需要對while(0==IRQ_flag)處理時(shí),在函數里加入一個(gè)NOP指令,以此規避GCC編譯器優(yōu)化的問(wèn)題造成IRQ_flag只判斷一次。
2.使用ee_printf()函數,減少代碼體積。
3. 在程序里有使能中斷時(shí),在使能單個(gè)中斷后,需要開(kāi)啟中斷總開(kāi)關(guān),否則會(huì )出現無(wú)法進(jìn)入中斷!。例如:
  Interrupt_Enable(EXIT9_5_int_ID);//CLIC使能EXIT中斷   SYS_Interrupt_Enable(); CLIC開(kāi)總中斷
那么,這里,硬件SPI,串口打印,GPIO中斷等外設就操作完了。個(gè)人能力有限,歡迎大家批評指正。
本文地址:http://selenalain.com/thread-797819-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)在線(xiàn)工具

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页