当前位置: 首页 > news >正文

违法网站建设国外服务器六安网站开发

违法网站建设国外服务器,六安网站开发,md风格WordPress,dw网页设计教程视频SPI总线是我们常用的串行设备接口#xff0c;一般情况下我们都会适应硬件SPI接口#xff0c;但有些时候当硬件端口不足时#xff0c;我们也希望可以使用软件来模拟SPI硬件接口#xff0c;特别是要求不是很高的时候。在这一篇中我们将来讨论如何使用GPIO和软件来模拟SPI通讯…  SPI总线是我们常用的串行设备接口一般情况下我们都会适应硬件SPI接口但有些时候当硬件端口不足时我们也希望可以使用软件来模拟SPI硬件接口特别是要求不是很高的时候。在这一篇中我们将来讨论如何使用GPIO和软件来模拟SPI通讯接口。 1、功能概述 SPI即串行外设接口是一种同步串行通讯接口用于微处理器及控制器和外围扩展芯片之间的串行连接现已发展成为一种工业标准。 1.1、物理层 SPI总线在物理层通常使用3条总线及1条片选线3条总线分别为 SCK、 MOSI、 MISO片选线为NSS它们的作用介绍如下   NSS( Slave Select)从设备选择信号线常称为片选信号线。在SPI协议中没有设备地址所以需要使用NSS信号线来寻址当主机要选择从设备时把该从设备的NSS信号线设置为低电平该从设备即被选中即片选有效接着主机开始与被选中的从设备进行SPI通讯。所以SPI通讯以NSS线置低电平为开始信号以NSS线被拉高作为结束信号。   SCK (Serial Clock)时钟信号线用于通讯数据同步。它由通讯主机产生决定了通讯的速率不同的设备支持的最高时钟频率不一样如 STM32 的 SPI 时钟频率最大为fpclk/2两个设备之间通讯时通讯速率受限于低速设备。   MOSI (Master Output Slave Input)主设备输出/从设备输入引脚。主机的数据从这条信号线输出从机由这条信号线读入主机发送的数据即这条线上数据的方向为主机到从机。   MISO(Master Input, Slave Output)主设备输入/从设备输出引脚。主机从这条信号线读入数据从机的数据由这条信号线输出到主机即在这条线上数据的方向为从机到主机。   对于使用SPI总线来进行通讯的设备一台主机可以与多台从机进行通讯时钟与数据总线为公用片选线每台从机都是独立的具体连接方式如下图所示 也就是说有多个SPI从设备与SPI主机通讯时设备的时钟线和总线数据线 SCK、MOSI及MISO同时并联到相同的SPI总线上即无论有多少个从设备都共同只使用这 3 条总线。而每个从设备都拥有独立的一条NSS信号线即有多少个从设备就有多少条片选信号线。 1.2、协议层 我们已经简述了SPI总线的物理连接方式接下来我们再来了解一下具体的通讯协议。在了解协议前我们需要清楚两个概念即时钟的极性和时钟的相位。   所谓时钟极性通常称作CPOL即是指在空闲状态下时钟所处的电平状态。如果SCLK在数据发送之前和之后的空闲状态是高电平那么就是CPOL1如果空闲状态SCLK是低电平那么就是 CPOL0。   而时钟的相位通常称作CPHA就是指数据采样是在时钟脉冲的第1个跳变沿还是在第2个跳变沿。如果在SCK的第1个跳变沿进行数据采样则CPHA0如果在SCK的第2个跳变沿采样则CPHA1。   在通讯协议中根据CPOL和CPHA的取值不同存在4种不同的配置方式不同的配置方式对应不同的通讯模式。   1当CPOL0CPHA0时空闲状态时钟SCK的电平要保持在低电平而数据的采样时刻在时钟脉冲的奇数跳变边沿其时序图如下 2当CPOL0CPHA1时空闲状态时钟SCK的电平要保持在低电平而数据的采样时刻在时钟脉冲的偶数跳变边沿其时序图如下 3当CPOL1CPHA0时空闲状态时钟SCK的电平要保持在高电平而数据的采样时刻在时钟脉冲的奇数跳变边沿其时序图如下 4当CPOL1CPHA1时空闲状态时钟SCK的电平要保持在高电平而数据的采样时刻在时钟脉冲的偶数跳变边沿其时序图如下 根据这时钟情况将SPI总线的工作模式分为4种如下图所示 而只有主机与从机拥有相同的工作模式时主从机之间才可以正常通讯。在实际应用中“模式 0”与“模式 3”是比较常见的工作模式但在我们的驱动设计中应该兼顾这4种模式以具备更广泛的适应性。 2、驱动设计与实现 我们已经简要的描述了SPI通讯总线的物理连接和通讯协议接下来我们将根据其协议的特性设计并实现基于GPIO模拟的SPI总线驱动。 2.1、对象定义 我们依然使用基于对象的思想来实现基于GPIO模拟的SPI总线驱动。既然是基于对象那么在使用一个对象之前我们需要先获得这个对象。所以我们必须先定义一个基于GPIO模拟的SPI总线的对象。 2.1.1、对象的抽象 我们要得到基于GPIO模拟的SPI总线的对象需要先分析其基本特性。一般来说一个对象至少包含属性与操作两方面的特性。接下来我们就来从这两个方面思考一下基于GPIO模拟的SPI总线的对象。   我们首先来考虑对象的属性作为属性肯定是用于标识或记录对象特征的东西。我们在前面已经了解到SPI总线的一些特点和独特设定那么这些特点和设定是否能成为对象的属性呢   我们考虑到作为同步总线SPI总线的控制需要时钟这关系到SPI总线的通讯速率这一通讯速率不仅配置SPI总线的工作方式也标识当前的工作状态所以我们将工作速率作为模拟SPI总线对象的一个属性。在前面我们讨论过SPI总线的工作模式工作模式由CPOL和CPHA决定所以在初始化总线时就会确定工作模式所以我们需要记录CPOL和CPHA我们将CPOL和CPHA也作为对象的属性。   接下来我们考虑GPIO模拟SPI总线的操作问题。我们将那些对象要实现的并且依赖于具体的平台的行为实现定义为对象的操作。对于GPIO模拟SPI总线来说我们需要通过总线发送数据和接收数据而接收和发送的实现都依赖于具体的软硬件平台所以我们将发送数据和接收数据定义为对象的操作。SPI总线作为同步总线需要时钟而时钟操作也是依赖于具体的软硬件平台来实现所以我们将始终的控制也作为对象的操作。   根据上述我们对GPIO模拟SPI总线的分析我们可以定义GPIO模拟SPI总线对象类型如下 /*定义GPIO模拟SPI接口对象*/ typedef struct SimuSPIObject{uint16_t CPOL:1;uint16_t CPHA:1;uint16_t period:14; //确定速度为大于0K小于等于400K的整数默认为100Kvoid (*SetSCKPin)(SimuSPIPinValueType op); //设置SCL引脚void (*SetMOSIPin)(SimuSPIPinValueType op); //设置SDA引脚uint8_t (*ReadMISOPin)(void); //读取SDA引脚位void (*Delayus)(volatile uint32_t period); //速度延时函数 }SimuSPIObjectType;2.1.2、对象初始化 我们知道在使用一个对象之前需要先对其进行初始化所以这里我们来考虑GPIO模拟SPI对象的初始化函数。一般来说初始化函数需要处理几个方面的问题。一是检查输入参数是否合理二是为对象的属性赋初值三是对对象做必要的初始化配置。据此我们设计GPIO模拟SPI对象的初始化函数如下 /* GPIO模拟SPI通讯初始化 */ void SimuSPIInitialization(SimuSPIObjectType *simuSPIInstance,//初始化的模拟SPI对象uint32_t speed, //时钟频率SimuSPICPOLType CPOL, //时钟极性SimuSPICPHAType CPHA, //时钟频率SimuSPISetSCKPin setSCK, //SCK时钟操作函数指针SimuSPISetMOSIPin setMOSI, //MOSI操作函数指针SimuSPIReadMISOPin getMISO, //MISO操作函数指针SimuSPIDelayus delayus //微秒延时操作函数指针) {if((simuSPIInstanceNULL)||(setSCKNULL)||(setMOSINULL)||(getMISONULL)||(delayusNULL)){return;}simuSPIInstance-SetSCKPinsetSCK;simuSPIInstance-SetMOSIPinsetMOSI;simuSPIInstance-ReadMISOPingetMISO;simuSPIInstance-Delayusdelayus;/*初始化速度,默认100K*/if((speed0)(speed500)){simuSPIInstance-period500/speed;}else{simuSPIInstance-period5;}simuSPIInstance-CPOLCPOL;simuSPIInstance-CPHACPHA;/*拉高总线使处于空闲状态*/if(simuSPIInstance-CPOLSimuSPI_POLARITY_LOW){simuSPIInstance-SetSCKPin(SimuSPI_Reset);}else{simuSPIInstance-SetSCKPin(SimuSPI_Set);} }2.2、对象操作 我们已经定义了对象类型也实现了对象的初始化函数但我们还没有实现对象的具体操作所以接下来我们就来实现对象的具体操作。 2.2.1、数据的发送 在我们使用SPI来实现数据通讯时免不了要发送数据所以在我们使用GPIO模拟SPI端口时就需要解决数据发送的问题。这里我们考虑使用模拟SPI发送一个字节的问题因为发送多个字节无非是多重复几次。根据前面分析的在不同模式下的时序图我们可以编写GPIO模拟SPI发送一个字节的函数如下 /* 通过模拟SPI发送一个字节 */ static void SendByteBySimuSPI(SimuSPIObjectType *simuSPIInstance,uint8_t byte) { // uint8_t length[2]{8,16};if(simuSPIInstance-CPOLSimuSPI_POLARITY_LOW){/*拉低SCL引脚准备数据传输*/simuSPIInstance-SetSCKPin(SimuSPI_Reset);if(simuSPIInstance-CPHASimuSPI_PHASE_1EDGE) //模式0{for(uint8_t count 0; count 8; count){if(byte 0x80) //每次发送最高位{simuSPIInstance-SetMOSIPin(SimuSPI_Set);}else{simuSPIInstance-SetMOSIPin(SimuSPI_Reset);}byte 1; //发送一位后左移一位simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Reset);}}else //模式1{for(uint8_t count 0; count 8; count){if(byte 0x80) //每次发送最高位{simuSPIInstance-SetMOSIPin(SimuSPI_Set);}else{simuSPIInstance-SetMOSIPin(SimuSPI_Reset);}byte 1; //发送一位后左移一位simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);}}}else{/*拉低SCL引脚准备数据传输*/simuSPIInstance-SetSCKPin(SimuSPI_Set);if(simuSPIInstance-CPHASimuSPI_PHASE_1EDGE) //模式2{for(uint8_t count 0; count 8; count){if(byte 0x80) //每次发送最高位{simuSPIInstance-SetMOSIPin(SimuSPI_Set);}else{simuSPIInstance-SetMOSIPin(SimuSPI_Reset);}byte 1; //发送一位后左移一位simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Set);}}else //模式3{for(uint8_t count 0; count 8; count){if(byte 0x80) //每次发送最高位{simuSPIInstance-SetMOSIPin(SimuSPI_Set);}else{simuSPIInstance-SetMOSIPin(SimuSPI_Reset);}byte 1; //发送一位后左移一位simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);simuSPIInstance-SetSCKPin(SimuSPI_Set);}}} }2.2.2、数据的接收 对于SPI端口来说不光需要发送数据也需要从对方接收数据同样的我们再次考虑接收一个字节的情况。同样我们根据前面对不同模式下接收数据的时序要求可以编写接收一个字节的函数如下 /* 通过模拟SPI接收一个字节 */ static uint8_t RecieveByteBySimuSPI(SimuSPIObjectType *simuSPIInstance) {uint8_t receive 0;if(simuSPIInstance-CPOLSimuSPI_POLARITY_LOW){/*拉低SCL引脚准备数据传输*/simuSPIInstance-SetSCKPin(SimuSPI_Reset);if(simuSPIInstance-CPHASimuSPI_PHASE_1EDGE) //模式0{for(uint8_t count 0; count 8; count ){simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);receive 1;if(simuSPIInstance-ReadMISOPin()){receive;}simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);}}else //模式1{simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);for(uint8_t count 0; count 8; count ){simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);receive 1;if(simuSPIInstance-ReadMISOPin()){receive;}simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);}simuSPIInstance-SetSCKPin(SimuSPI_Reset);}}else{/*拉低SCL引脚准备数据传输*/simuSPIInstance-SetSCKPin(SimuSPI_Set);if(simuSPIInstance-CPHASimuSPI_PHASE_1EDGE) //模式2{for(uint8_t count 0; count 8; count ){simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);receive 1;if(simuSPIInstance-ReadMISOPin()){receive;}simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);}}else //模式3{simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);for(uint8_t count 0; count 8; count ){simuSPIInstance-SetSCKPin(SimuSPI_Set);simuSPIInstance-Delayus(simuSPIInstance-period);receive 1;if(simuSPIInstance-ReadMISOPin()){receive;}simuSPIInstance-SetSCKPin(SimuSPI_Reset);simuSPIInstance-Delayus(simuSPIInstance-period);}simuSPIInstance-SetSCKPin(SimuSPI_Set);}}return receive; }3、驱动的使用 我们已经设计并实现了GPIO模拟SPI总线的驱动程序接下来我们将基于这一驱动设计一个简单的用例以验证驱动程序的正确性。 3.1、声明并初始化对象 我们是基于对象来实现GPIO模拟SPI驱动的所以在开始之前我们需要声明一个模拟SPI对象如下 SimuSPIObjectType simuSPI;声明了这一对象之后我们还需要对这一变量进行初始化才能使用。前面我们已经实现了对象变量的初始化函数使用这一函数就可方便的初始化对象变量该函数有多个输入数 SimuSPIObjectType *simuSPIInstance,//初始化的模拟SPI对象 uint32_t speed, //时钟频率 SimuSPICPOLType CPOL, //时钟极性 SimuSPICPHAType CPHA, //时钟相位 SimuSPIDataSizeType dataSize,//数据长度 SimuSPISetSCKPin setSCK, //SCK时钟操作函数指针 SimuSPISetMOSIPin setMOSI, //MOSI操作函数指针 SimuSPIReadMISOPin getMISO, //MISO操作函数指针 SimuSPIDelayus delayus //微秒延时操作函数指针在这些参数中simuSPIInstance为我们想要初始化的对象变量的指针。时钟极性、时钟相位以及数据长度都是枚举量我们根据实际的使用要求选择输入即可。时钟频率为我们希望的时钟速度最大500K。而余下的几个参数则都是回调函数的指针。而这几个函数则是我们在应用程序中需要实现的它们的原型如下 //设置SCL引脚 typedef void (*SimuSPISetSCKPin)(SimuSPIPinValueType op); //设置SDA引脚 typedef void (*SimuSPISetMOSIPin)(SimuSPIPinValueType op); //读取SDA引脚位 typedef uint8_t (*SimuSPIReadMISOPin)(void); //速度延时函数 typedef void (*SimuSPIDelayus)(volatile uint32_t period);这些函数的实现与具体的应用平台有关我们在STM32F407上基于HAL库实现的这些函数如下 //设置SCL引脚 void SPISCKOperation(SimuSPIPinValueType op) {GPIO_PinState PinState(GPIO_PinState)op;HAL_GPIO_WritePin(GPIOSPI, SPISCK, PinState); }//设置SDA引脚 void SPIMOSIOperation(SimuSPIPinValueType op) {GPIO_PinState PinState(GPIO_PinState)op;HAL_GPIO_WritePin(GPIOSPI, SPIMOSI, PinState); }//读取SDA引脚位 uint8_t SPIMISORead(void) {if(HAL_GPIO_ReadPin(GPIOSPI, SPIMISO)){return 1;}return 0; }而延时操作函数则采用我们系统中通用的Delayus。有了这些参数后我们合一调用初始化函数对对象变量进行初始化如下 /* GPIO模拟SPI通讯初始化 */SimuSPIInitialization(simuSPI,//初始化的模拟SPI对象500, //时钟频率SimuSPI_POLARITY_LOW, //时钟极性SimuSPI_PHASE_1EDGE, //时钟频率SimuSPI_DataSize_8Bit,//数据长度SPISCKOperation, //SCK时钟操作函数指针SPIMOSIOperation, //MOSI操作函数指针SPIMISORead, //MISO操作函数指针Delayus //微秒延时操作函数指针);3.2、基于对象进行操作 初始化这个对象变量后我们就可以基于它操作这一对象了。我们基于驱动实现一个简单的读写数据的操作如下 /* 使用模拟SPI读写数据*/ void SimuSPIDataExchange(void) {uint8_t wDatas[3];uint8_t rDatas[3];/* 通过模拟SPI向从站写数据 */WriteDataBySimuSPI(simuSPI,wDatas,3,1000);HAL_Delay(10);/* 通过模拟SPI自从站读数据 */ReadDataBySimuSPI(simuSPI,rDatas, 3,1000);HAL_Delay(10);/* 通过模拟SPI实现对从站先写数据紧接读数据组合操作 */WriteReadDataBySimuSPI(simuSPI, wDatas,3,rDatas, 3,1000);HAL_Delay(10);/* 通过模拟SPI实现对从站同时写和读数据组合操作*/WriteWhileReadDataBySimuSPI(simuSPI, wDatas,rDatas,3,1000);}我们分别测试了读取数据、下发数据、同时写和读数据以及写完后再读等几种情况的测试效果还是比较理想的。 4、应用总结 在这一篇中我们设计并实现了基于GPIO模拟的SPI接口驱动程序。并在此基础上设计了一个简单的测试应用。我们通过GPIO模拟的SPI接口向SPI接口的Flash中写数据、读数据、同时读写和先写后读试验都没有问题。   在使用驱动程序时需要注意由于是使用GPIO模拟的SPI端口其速度是受到限制的目前最快能够支持到500K再快就不能支持了。所以这个驱动程序只能应用于通讯速度小于500K的设备。 欢迎关注
http://www.ihoyoo.com/news/21605.html

相关文章:

  • 如何更换网站服务器合肥网站建设设计公司
  • 网站上线流程青岛网站建设‘’
  • 智慧团建信息系统网站登录wordpress酒店预订主题
  • 黄石网站设计制作海口网站建设
  • 资讯网站 怎样 增强用户粘度温州小程序开发哪家好
  • 免费企业黄页网站网址上海门户网站制作公司
  • 创造与魔法官方网站做自己网络营销方案3000字
  • 建设银行网站功能介绍wordpress posts
  • 郑州做网站软件网站模板免费
  • 网站前后端的关系模板网站建设 报价
  • 珠海网站建设找哪家好网站代码跑偏了怎么做
  • 商丘网站建设想象力网络可以看小视频的浏览器
  • 个人网站做什么类型好菏泽哪里有做网站的
  • 哪里的网站建设免费网页制作软件下载
  • 购物网站建设源码免费的asp网站
  • 网站经营许可备案号企业网站托管后果
  • 制作网站公司服务器租赁一年的费用广州网站建设q.479185700棒
  • 开封市住房和城乡建设局网站404免费模板下载
  • 网站建设的岗位职责恢复被百度k网站 关键词收录
  • 怎么做下载类的网站wordpress 站库分离
  • 成功网站管理系统密云网站建设
  • 公众号如何推广wordpress 链接优化
  • 万博法务网站十大广告设计公司简介
  • 利川市网站建设米课中有个内贸网站建设
  • 江苏省住房和城乡建设局网站高端网站的制作
  • wordpress电影网站主题设计网站怎么做的
  • 上海建设网站长春盛网网站建设
  • 做设计的公司的网站公司网站制作需要多少钱义乌
  • 做网站定制wordpress本地传图片
  • 辽宁朝阳哪家做网站好南郊做网站