目的:

通过CSM32RV20开发平台,使用硬件SPI接口与Si24R1进行通信,通信成功后,通过串口打印数据。

实现过程:

1.中断向量表和系统时钟初始化

在IDE里新建项目后,都会包含CLIC_Init()和System_Clock_Init()两个函数。中断向量表初始化,系统中断初始化,用户无需关心。系统时钟初始化函数中,可以方便的选中时钟源、时钟分频系数、外设时钟使能和RC频率选择。

int main(void)
{///----System Init ---------------------------------------------------------------------------------------------CLIC_Init();//中断向量表初始化System_Clock_Init();//系统时钟初始化
void System_Clock_Init(void)//系统时钟初始化
{//时钟源开关CMU->SRC_EN  = 1<<1   //RCOSC    bit[1]:0-off, 1-on|1<<0;  //crystal  bit[0]:0-off, 1-on//外设和内核时钟来源选择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//设置时钟分频系数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//外设时钟使能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即可以用作烧录使用(开发板串口默认使用UART1),又可以调用打印,方便数据输出。UART1:PA6:TX1,复用配置AF0(默认)。PA5:RX1,复用配置AF0(默认)。

UART_Init_case1(UART1);   //串口初始化

由于开发板上使用的晶振为32MHz,那么我们设置0x0116<<8串口波特率就是115200

   UARTx->CTRL = 0<<25        //接收中断使能: 0-off,1-on|0<<24        //发送中断使能:0-off,1-on|0x0116<<8    //波特率(对应16M时钟)://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         //发送数据bit8|0<<2;        //接收数据bit8

2.2外设初始化(SPI)

SPI初始化,选中非中断模式。Si24R1采用四线制SPI,与MCU连接共6根线。Si24R1芯片引脚介绍(MOSI和MISO直接与MCU的硬件SPI对应连接即可,即MOSI与SPI1_MOSI连接)。CE,芯片开启信号,激活 RX 或 TX 模式。CSN,SPI 片选信号。SCK,SPI 时钟信号。MOSI,SPI 输入信号。MISO,SPI输出信号。IRQ,可屏蔽中断信号(可以通过0x00寄存器CONFIG配置屏蔽),低电平有效。

 SPI_Init_case1(SPI1);     //SPI初始化,非中断模式

CSM32RV20,硬件SPI1引脚说明:PA2-SPI1_SCK,PA3-SPI1_MISO,PA4_SPI1_MOSI.

   if(SPIx==SPI1){//用户自选CSN,软件操作片选信号//配置SCKGPIO_MODE_Init(GPIOA, PIN2, GPIO_MODE_AF);  //PA2复用模式GPIO_AF_Init(GPIOA,  PIN2,  GPIO_AF0);  //PA2复用到SPI1_SCK//配置MISOGPIO_MODE_Init(GPIOA, PIN3, GPIO_MODE_AF);  //PA3复用模式GPIO_AF_Init(GPIOA,  PIN3,  GPIO_AF0);  //PA3复用到SPI1_MISO//配置MOSIGPIO_MODE_Init(GPIOA, PIN4, GPIO_MODE_AF);  //PA4复用模式GPIO_AF_Init(GPIOA,  PIN4,  GPIO_AF0);  //PA4复用到SPI1_MOSI}

根据Si24R1的SPI协议,CPHA时钟相位和CPOL的时钟极性(SCK空闲时状态为低电平,上升沿采样下降沿输出),选中SPI模式0。SPI速率选择为8分频-4MHz。使用软件CSN控制

SPIx->CTRL = 0x0<<8     //中断使能:0-关闭,1-开启|0x0<<7     //时钟极性:0-低电平,1-高电平|0x0<<6     //时钟相位:0-前沿采样,后沿输出,1-前沿输出,后沿采样,|0x1<<4     //SPI使能:0-关闭,1-使能|0x3;       //时钟分频: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-GPIO7
void SPI1_CSN_Init_case1(void)//CFG: CE-GPIO9,CSN-GPIO8,IRQ-GPIO7
{GPIO_MODE_Init(GPIOA,PIN8,GPIO_MODE_OUTPUT);//CSNGPIO_Write(GPIOA,PIN8,GPIO_SET);//CSN=1GPIO_MODE_Init(GPIOA,PIN9,GPIO_MODE_OUTPUT);//CEGPIO_Write(GPIOA,PIN9,GPIO_RESET);//CE=0GPIO_MODE_Init(GPIOA,PIN7,GPIO_MODE_INPUT);//IRQ}

2.4外设初始化(中断)

中断IRQ引脚,开发板上选择为PA7。

   GPIO_EXIT_Init_case4(GPIOA, PIN7);//检测下降沿Interrupt_Enable(EXIT9_5_int_ID);//CLIC使能EXIT中断SYS_Interrupt_Enable(); CLIC开总中断
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通信模式,一种是兼容模式,两者的区别就在于是否有包控制字,包控制可以实现动态负载长度,ACK通信,ACKPAYLAOD通信等。
Si24R1通信模式:


兼容模式:

4.Si24R1模块

Si24R1模块采用亿佰特的E01C

5. SPI函数

SPI读写函数:SPI1读写一个字节

uint8_t spi_rw_byte(uint8_t byte)
{uint8_t a;SPI_Transceive(SPI1,&byte,&a,1);return  a;
}

SPI写寄存器:写数据value到reg寄存器,同时返回寄存器值

uint8_t spi_rw_reg(uint8_t reg,uint8_t value){uint8_t status;reg |= W_REGISTER ;                        //写寄存器命令GPIO_Write(GPIOA,PIN8,GPIO_RESET);status=spi_rw_byte(reg);             //选择寄存器,同时返回状态字spi_rw_byte(value);GPIO_Write(GPIOA,PIN8,GPIO_SET);return status;                //返回状态寄存器}

SPI读寄存器:

//========从reg寄存器中读一个字节的数据========
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 );            //返回状态寄存器
}

SPI读BUFF:

//函数:spi_read_buf()
//功能:从reg寄存器读出bytes个字节,通常用来读取接收通道数据 或 接收/发送地址
//=====================================================================================
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);                      // 选择寄存器,同时返回状态字for(i = 0; i < bytes; i++){pBuf[i] = spi_rw_byte(0);    // 逐个字节从Si24R1读出}GPIO_Write(GPIOA,PIN8,GPIO_SET);                             // CSN拉高,结束数据传输return(status);                            // 返回状态寄存器
}

SPI写BUFF:

//函数:spi_write_buf()
//功能:把pBuf缓存中的数据写入到Si24R1,通常用来写入发射通道数据 或 接收/发送地址
//=====================================================================================
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置低,开始传输数据status    = spi_rw_byte(reg);      // 选择寄存器,同时返回状态字for(i = 0; i < bytes; i++){spi_rw_byte(pBuf[i]);        // 逐个字节写入Si24R1}GPIO_Write(GPIOA,PIN8,GPIO_SET);       // CSN拉高,结束数据传输return(status);                  // 返回状态寄存器
}

6. TX_mode和RX_mode配置

TX_mode: CE拉低后,配置发射地址、发射地址宽度、射频信道、传输速率,发射功率,配置发射模式、CRC、清除STATUS寄存器的标志位!!!(可能在调试程序或者异常退出,没有清除STATUS,但是芯片没断电,可能IRQ的电平一直为低,最好就在初始化时清除STATUS寄存器的标志位。

spi_rw_reg(STATUS,0xff);
//Si24R1 NOACK 发射模式
void Si24R1_Tx_Mode(void)
{GPIO_Write(GPIOA,CE_Pin,GPIO_RESET);spi_write_buf(TX_ADDR, TX_ADDRESS, 5); // 写入发送地址spi_rw_reg(FEATURE, 0x01); // 使能 W_TX_PAYLOAD_NOACK 命令spi_rw_reg(SETUP_AW, 0x03); // 5 byte Address widthspi_rw_reg(RF_CH, 2); // 选择射频通道0x40spi_rw_reg(RF_SETUP, 0x0f); // 数据传输率 2Mbpsspi_rw_reg(CONFIG, 0x0e); //配置为发射模式、CRC 为 2Bytesspi_rw_reg(STATUS,0xff);//GPIO_Write(GPIOA,CE_Pin,GPIO_SET);
}

RX_mode: 发射端的配置与接收端的配置一致即可

//Si24R1 NOACK 接收模式
void Si24R1_Rx_Mode(void)
{GPIO_Write(GPIOA,CE_Pin,GPIO_RESET);spi_write_buf(RX_ADDR_P0, TX_ADDRESS, 5); // 写入接收地址
//  spi_rw_reg(FEATURE, 0x01); // 使能 W_TX_PAYLOAD_NOACK 命令spi_rw_reg(EN_RXADDR , 0x01); // 使能接收通道spi_rw_reg(RF_CH, 2); // 选择射频通道0x40spi_rw_reg(RX_PW_P0 ,TX_PLOAD_WIDTH ); // 设置接收通道0负载数据宽度spi_rw_reg(SETUP_AW, 0x03);                                  // 5 byte Address widthspi_rw_reg(RF_SETUP, 0x0f); // 数据传输率 2Mbpsspi_rw_reg(CONFIG, 0x0f); //配置为接收方、RC 为 2Bytesspi_rw_reg(STATUS,0xff);
//
//  GPIO_Write(GPIOa,CE_Pin,GPIO_SET);
}

Si24R1_TxPacket():发射函数,主要是给TX_FIFO填充数据,CE拉高后就会发射出去。其中要注意:发射前最好擦除FIFO,再填写FIFO,这样对异常的数据发送可以起到一定的屏蔽作用,否则可能会陷入始终发上一包写入数据的怪圈。等到IRQ下降沿中断后,判断是否为发射完成中断,完成即返回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模式时,应使用命令 W_TX_PAYLOAD_NOACKspi_write_buf(W_TX_PAYLOAD_NOACK,TX_BUF,TX_PLOAD_WIDTH);//写数据到TX BUF//   spi_write_buf(W_TX_PAYLOAD,TX_BUF,TX_PLOAD_WIDTH);//写数据到TX BUFGPIO_Write(GPIOA,CE_Pin,GPIO_SET);//启动发送Delay32M_us(10);while(0==IRQ_flag){NOP;     //切记一定得加NOP指令,由于GCC编译器优化问题,程序会只调用一次中断标志。}//等待发送完成IRQ_flag=0;sta = spi_rd_reg(STATUS);        // 返回状态寄存器spi_rw_reg(W_REGISTER+STATUS,sta); //清除TX_DS或MAX_RT中断标志if(sta&MAX_RT)//达到最大重发次数{spi_rw_reg(FLUSH_TX,0xff);//清除TX FIFO寄存器return MAX_RT;}if(sta&TX_OK)//发送完成{return TX_OK;}return 0xff;//其他原因发送失败
}

其中,需要注意的是:在等待中断的标志IRQ_flag时,如果直接判断,由于GCC编译器优化,我们利用IDE的反汇编功能,查看下两者的区别:

while(0==IRQ_flag);

while(0==IRQ_flag){NOP;    }

7.通信判断

main()函数中,调用Si24R1_TxPacket();函数,判断返回值是否为发射完成TX_OK标志,闪灯+打印即可。打印这里,虽然库函数里有printf()和ee_printf(),都支持,但是推荐使用ee_printf()函数,这个是简化版的printf函数(而不是C运行库中提供的printf函数),以此生成的代码体积就会更小。

       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");}elseDelay32M_ms(20);}


总结:

1.注意在等中断IRQ产生后的IRQ_flag时,需要对while(0==IRQ_flag)处理时,在函数里加入一个NOP指令,以此规避GCC编译器优化的问题造成IRQ_flag只判断一次。
2.使用ee_printf()函数,减少代码体积。
3. 在程序里有使能中断时,在使能单个中断后,需要开启中断总开关,否则会出现无法进入中断!!。例如:

   Interrupt_Enable(EXIT9_5_int_ID);//CLIC使能EXIT中断SYS_Interrupt_Enable(); CLIC开总中断

那么,这里,硬件SPI,串口打印,GPIO中断等外设就操作完了。个人能力有限,欢迎大家批评指正。

CSM32RV20开发(二):Si24R1 通信模式调试相关推荐

  1. 【安卓开发 】Android初级开发(二)Activity启动模式

    Activity页面跳转在业务逻辑页面添加以下代码 //跳转到下一个activityIntent intent = new Intent(this,MainActivity2.class);start ...

  2. WCF 宿主与通信模式(二)

    宿主 每个WCF服务都必须托管在Windows进程中,该进程称为宿主进程(host process) 单个宿主进程可以托管多个服务,相同的服务类型也可以托管在多个宿主进程中. wcf中托管服务一般有一 ...

  3. MIP开发教程(二) 使用MIP-CLI工具调试MIP网页

    初始化 MIP 配置 新建一个 MIP 网页 编写 MIP 网页代码 校验 MIP 网页 调试 MIP 网页 1. 初始化 MIP 配置 首先在html目录下进行初始化 MIP 配置: $ mip i ...

  4. 网页游戏开发入门教程二(游戏模式+系统)

    2019独角兽企业重金招聘Python工程师标准>>> 一.游戏模式 目前webgame游戏模式大体上可以分为以下四类: 1.玩家拥有一个城市,不断的升级城市内建筑,建筑可以自动获得 ...

  5. Qt安卓app开发,蓝牙通信调试助手,经典蓝牙通信调试工具

    目录 软件说明 app界面 源码下载地址 软件说明 1.基于Qt开发,QBluetoothSocket通信: 2.开/关蓝牙.搜索/停止搜索设备.Ascii/Hex收发.收发延迟设置.收发计数等功能: ...

  6. SAP RFC通信模式

    在网络技术中,数据通信可以大致划分为两种基本模式:同步通信和异步通信. 其本义是:异步通信时,通信双方时钟允许存在一定误差:同步通信时,双方时钟的允许误差较小.在SAP的系统间的通信过程中,也借用术语 ...

  7. 智能家居项目开发: 设计模式(工厂模式)+ 线程池 + Socket (持续更新中)

    智能家居项目开发 一.智能家居功能细节拆分 控制区: 外设区: 面向对象类和对象的概念 结构体新玩法 二.工厂模式 1. 工厂模式的概念 2. 工厂模式的实现 3. 工厂模式使用及功能验证 三.智能家 ...

  8. STM32CubeIDE开发(二十六), STM32的CAN总线开发要点

    一.CAN总线简介 1.1 CAN概述 CAN是Controller Area Network(控制区域网络) 的缩写,是ISO国际标准化的串行通信协议.由德国电气商博世公司在1986年率先提出.此后 ...

  9. linux服务器开发二(系统编程)--线程相关

    线程概念 什么是线程 LWP:Light Weight Process,轻量级的进程,本质仍是进程(在Linux环境下). 进程:独立地址空间,拥有PCB. 线程:也有PCB,但没有独立的地址空间(共 ...

  10. 嵌入式系统 实验二 串口通信实验

    实验二 串口通信实验 一.实验目的 1.)了解 USART 的基本特性: 2.)掌握用库函数操作 USART 的方法: 3.)掌握如何使用 STM32 的串口发送和接收数据. 二.实验环境 1.)硬件 ...

最新文章

  1. LeetCode 罗马数字与阿拉伯数字的转换
  2. python bind sock_python SOCKET编程详细介绍
  3. dnf机器人猜数字奖励_DNF:周年庆策划啪啪打脸,工作人员也出错误,难道又是临时工的锅?...
  4. 我连饭也顾不上HAO3GP整站源码
  5. java+逆向工程怎么运行_MyBatis逆向工程的创建和使用
  6. java中虚拟机命令:jstack使用方法
  7. 2018年7月第一周网站建站笔记
  8. js中数组增删查改unshift、push、pop、shift、slice、indexOf、concat、join
  9. 云鲸扫拖一体机器人说明书_云鲸小白鲸扫拖一体机器人好用吗?真实的测评带你走进智能化家居时代...
  10. SQL2016安装错误:安装程序无法与下载服务器联系。请提供 Microsoft R Open 和 Microsoft R Server 安装文件的位置
  11. JAVA初学者推荐《Java开发实战经典》李兴华著
  12. layui文档通读笔记
  13. 取消计算机触摸板,笔记本电脑触摸板如何打开和关闭
  14. Mac 下 Chrome 谷歌浏览器 快捷键
  15. 局域网打印机共享怎么设置_一篇文章弄懂局域网打印机共享
  16. 监听imput框的内容变化
  17. Java多线程由易到难
  18. 服务器被黑客攻击快速解决方案
  19. 2019暑假牛客训练赛(补题及笔记)
  20. 整理:JavaScript 各种转型函数与类型转换细节

热门文章

  1. 鸿蒙OS产业链上市公司梳理
  2. 按键精灵---大漠完美注册
  3. 使用SDKMAN来安装JDK和管理多个JDK版本
  4. html控制萤石云摄像头转动,萤石云摄像头直播带云台控制代码
  5. 渗透测试技术_Nessus工具(一)Linux centos7下 Nessus8.13的下载、安装
  6. 如何正确使用QTcpSocket的readyRead信号?
  7. STVP下载STM8单片机提示Verify error at address 0xxxxx的问题解决
  8. 微信小程序 弹窗(模态框)遮罩层 弹窗右上角按钮关闭
  9. 电机PID控制补充篇-野火上位机串口协议介绍
  10. 3.微信小程序--快速开发UI界面