硬件SPI实现
2017-10-19 18:53
134 查看
emmmm,,,,话说这个硬件SPI,,,做成了,再回过头来看,也特么真的没啥,,,,,但是做不成,哪都是问题。。。。
借此仅分享下我的经验,希望您可以少走弯路。。。
嗯,,,,其实在这之前我做单片机的SPI通信没有成功,于是就先做了SPI的W25Q16的读写,,,,可以参考这里
话补多少,上最终代码。。。
实验手札:
问题大概想了一下,只要有三个
1、具体到各个寄存器的使用,当时没弄太懂,太过心急。。。磨刀不误砍柴工,,,切记切记啊。。。
2、用李基佬的15的最小系统,特么谁知道背面有个自锁开关,,,我一不小心就按关了,,,导致调试的时候好几次情况都很意外。。。
3、关于单片机的封装没仔细看清,以及要不要用到复用引脚AUXR/AUXR1切换。。。
嗯,大概就是这样,咱们看代码!!!
主机
从机
为了更方便一点,把主机从机做到了一个程序里面。
只需要下载的时候主机define上master,而从机注释掉即可
手札:
1、注意自己连的是复用后的IO口,还是原装的,要不要进行端口转换。
2、注意两块SPI进行通信的时候,要MOSI、MISO、SCK、对应连接。
3、要共VCC、共GND。
看程序吧。。。
借此仅分享下我的经验,希望您可以少走弯路。。。
嗯,,,,其实在这之前我做单片机的SPI通信没有成功,于是就先做了SPI的W25Q16的读写,,,,可以参考这里
单主单从(忽略片选)
22.1184M 9600话补多少,上最终代码。。。
实验手札:
问题大概想了一下,只要有三个
1、具体到各个寄存器的使用,当时没弄太懂,太过心急。。。磨刀不误砍柴工,,,切记切记啊。。。
2、用李基佬的15的最小系统,特么谁知道背面有个自锁开关,,,我一不小心就按关了,,,导致调试的时候好几次情况都很意外。。。
3、关于单片机的封装没仔细看清,以及要不要用到复用引脚AUXR/AUXR1切换。。。
嗯,大概就是这样,咱们看代码!!!
主机
#include "stc15.h" // 注意宏定义后面没分号 bit SPI_Receive; // SPI 端口收到数据标志位 unsigned char SPI_buffer; // 保存SPI端口收到的数据 /************************************************************************** - 功能描述:STC15单片机串口1初始化,使用T1方式2自重载方式做波特率发生器 **************************************************************************/ void UART_init(void) // 9600bps@22.1184MHz { // 下面代码设置定时器1 TMOD |= 0x20; // 0010 0000 定时器1工作于方式2(8位自动重装方式) TH1 = 0xFA; // 波特率:9600 /22.1184MHZ TL1 = 0xFA; // 波特率:9600 /22.1184MHZ TR1 = 1; // 下面代码设置定串口 AUXR = 0x00; // 很关键,使用定时器1作为波特率发生器,S1ST2=0 SCON = 0x50; // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受) } void port_mode() // 端口模式 { P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00; P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00; } void main(void) 4000 { unsigned char tmpdata,SPI_status; port_mode(); // 所有IO口设为准双向弱上拉方式。 UART_init(); // 初始化串口,9600bps@22.1184MHz SPCTL=0xF0; // 主机 (或SPCTL=0xFC; ) while(1) // 主循环 { if(RI) // 判串口是否收到数据 { tmpdata=SBUF; // 读取串口中收到的数据 RI=0; P35=!P35; // 串口接收数据指示灯,调试时观察串口工作是否正常 // 将数据发送到从机SPI SPDAT=tmpdata; // SPI 发送数据 SPI_status=0; while(SPI_status==0) { SPI_status=SPSTAT; // 等待SPIF=1即等待SPI发送完毕 SPI_status=SPI_status&0x80; } SPSTAT=0xC0; // 清0标志位SPIF和WCOL SPI_buffer=SPDAT; // 保存收到的数据 SBUF=SPI_buffer; // 将接收到的数据从串口发送到计算机 while(TI==0); // 等待发送完毕 TI=0; // 清零串口发送中断标志 } } }
从机
#include "stc15.h" // 注意宏定义后面没分号 bit SPI_Receive; // SPI 端口收到数据标志位 unsigned char SPI_buffer; // 保存SPI端口收到的数据 void port_mode() // 端口模式 { P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00; P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00; } void main(void) { port_mode(); // 所有IO口设为准双向弱上拉方式。 SPCTL=0xE0; // 从机 (或SPCTL=0xEC; ) IE2=IE2|0x02; // ESPI(IE2.1)=1,允许SPIF产生中断 EA=1; // 开总中断 SPI_Receive=0; // 清标志字 while(1) // 主循环 { if (SPI_Receive) // 判收是否收到主机SPI发来的数据 { SPI_Receive=0; // 清0主单片机SPI端口收到数据标志位 SPDAT=SPI_buffer; // 将收到数据送SPDAT,准备下一次通讯时发回 } } } void SPI(void) interrupt 9 { SPSTAT=0xC0; // 清0标志位SPIF和WCOL SPI_buffer=SPDAT; // 保存收到的数据 SPI_Receive=1; // 设置SPI端口收到数据标志 }
为了更方便一点,把主机从机做到了一个程序里面。
只需要下载的时候主机define上master,而从机注释掉即可
手札:
1、注意自己连的是复用后的IO口,还是原装的,要不要进行端口转换。
2、注意两块SPI进行通信的时候,要MOSI、MISO、SCK、对应连接。
3、要共VCC、共GND。
看程序吧。。。
#include "STC15W4K.H" // 注意宏定义后面没分号 #define MASTER 1 // 作为从机程序时,将该行注释掉,其余都不用修改。 bit SPI_Receive; // SPI 端口收到数据标志位 unsigned char SPI_buffer; // 保存SPI端口收到的数据 /************************************************************************** - 功能描述:STC15单片机串口1初始化,使用T1方式2自重载方式做波特率发生器 **************************************************************************/ void UART_init(void) // 9600bps@22.1184MHz { // 下面代码设置定时器1 TMOD |= 0x20; // 0010 0000 定时器1工作于方式2(8位自动重装方式) TH1 = 0xFA; // 波特率:9600 /22.1184MHZ TL1 = 0xFA; // 波特率:9600 /22.1184MHZ TR1 = 1; // 下面代码设置定串口 AUXR = 0x00; // 很关键,使用定时器1作为波特率发生器,S1ST2=0 SCON = 0x50; // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受) } void Switch_port() // 根据硬件切换端口 { // AUXR1&=0XF3; //1111 0011 // AUXR1|=0X04; //0000 0100 } void port_mode() // 端口模式 { P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00; P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00; } void main(void) { unsigned char tmpdata,SPI_status; port_mode(); // 所有IO口设为准双向弱上拉方式。 #ifdef MASTER UART_init(); // 初始化串口,9600bps@22.1184MHz SPCTL=0xF0; // 主机 (或SPCTL=0xFC; ) Switch_port(); // 端口切换 #else SPCTL=0xE0; // 从机 (或SPCTL=0xEC; ) #endif SPSTAT=0xc0; // 清0标志位SPIF和WCOL IE2=IE2|0x02; // ESPI(IE2.1)=1,允许SPIF产生中断 EA=1; // 开总中断 SPI_Receive=0; // 清标志字 while(1) // 主循环 { #ifdef MASTER if(RI) // 判串口是否收到数据 { tmpdata=SBUF; // 读取串口中收到的数据 RI=0; P35=!P35; // 串口接收数据指示灯,调试时观察串口工作是否正常 // 将数据发送到从机SPI IE2&=0xfd; // ESPI(IE2.1)=0,禁止SPIF产生中断 SPDAT=tmpdata; // SPI 发送数据 SPI_status=0; while(SPI_status==0) { SPI_status=SPSTAT; // 等待SPIF=1即等待SPI发送完毕 SPI_status=SPI_status&0x80; } IE2|=0x02; // ESPI(IE2.1)=1,允许SPIF产生中断 continue; // 跳转到循环体最后结尾“}” 处执行程序 } if (SPI_Receive) // 判断是否接收到从SPI发回数据 { SPI_Receive=0; // 清0主单片机SPI端口收到从机数据标志位 TI=0; // 清零串口发送中断标志 SBUF=SPI_buffer; // 将接收到的数据从串口发送到计算机 while(TI==0); // 等待发送完毕 TI=0; // 清零串口发送中断标志 } #else if (SPI_Receive) // 判收是否收到主机SPI发来的数据 { SPI_Receive=0; // 清0主单片机SPI端口收到数据标志位 SPDAT=SPI_buffer; // 将收到数据送SPDAT,准备下一次通讯时发回 } #endif } } void SPI(void) interrupt 9 { SPSTAT=0xC0; // 清0标志位SPIF和WCOL SPI_buffer=SPDAT; // 保存收到的数据 SPI_Receive=1; // 设置SPI端口收到数据标志 }
单主单从(加入片选)
22.1184M 9600#include "STC15W4K.H" // 注意宏定义后面没分号 #define MASTER 1 // 作为从机程序时,将该行注释掉,其余都不用修改。 bit SPI_Receive; // SPI 端口收到数据标志位 unsigned char SPI_buffer; // 保存SPI端口收到的数据 sbit P2_4=P2^4; /************************************************************************** - 功能描述:STC15单片机串口1初始化,使用T1方式2自重载方式做波特率发生器 **************************************************************************/ void UART_init(void) // 9600bps@22.1184MHz { // 下面代码设置定时器1 TMOD |= 0x20; // 0010 0000 定时器1工作于方式2(8位自动重装方式) TH1 = 0xFA; // 波特率:9600 /22.1184MHZ TL1 = 0xFA; // 波特率:9600 /22.1184MHZ TR1 = 1; // 下面代码设置定串口 AUXR = 0x00; // 很关键,使用定时器1作为波特率发生器,S1ST2=0 SCON = 0x50; // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受) } void Switch_port() // 根据硬件切换端口 { // AUXR1&=0XF3; //1111 0011 // AUXR1|=0X04; //0000 0100 } void port_mode() // 端口模式 { P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00; P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00; } void main(void) { unsigned char tmpdata,SPI_status; port_mode(); // 所有IO口设为准双向弱上拉方式。 #ifdef MASTER UART_init(); // 初始化串口,9600bps@22.1184MHz SPCTL=0xF3; // 主机 (或SPCTL=0xFC; ) Switch_port(); // 端口切换 #else SPCTL=0x63; // 从机 (或SPCTL=0xEC; ) #endif SPSTAT=0xc0; // 清0标志位SPIF和WCOL IE2=IE2|0x02; // ESPI(IE2.1)=1,允许SPIF产生中断 EA=1; // 开总中断 SPI_Receive=0; // 清标志字 while(1) // 主循环 { #ifdef MASTER if(RI) // 判串口是否收到数据 { tmpdata=SBUF; // 读取串口中收到的数据 RI=0; P35=!P35; // 串口接收数据指示灯,调试时观察串口工作是否正常 // 将数据发送到从机SPI IE2&=0xfd; // ESPI(IE2.1)=0,禁止SPIF产生中断 P2_4=0; // 打开从机片选 SPDAT=tmpdata; // SPI 发送数据 SPI_status=0; while(SPI_status==0) { SPI_status=SPSTAT; // 等待SPIF=1即等待SPI发送完毕 SPI_status=SPI_status&0x80; } P2_4=1; // 关闭从机片选 IE2|=0x02; // ESPI(IE2.1)=1,允许SPIF产生中断 continue; // 跳转到循环体最后结尾“}” 处执行程序 } if (SPI_Receive) // 判断是否接收到从SPI发回数据 { SPI_Receive=0; // 清0主单片机SPI端口收到从机数据标志位 TI=0; // 清零串口发送中断标志 SBUF=SPI_buffer; // 将接收到的数据从串口发送到计算机 while(TI==0); // 等待发送完毕 TI=0; // 清零串口发送中断标志 } #else if (SPI_Receive) // 判收是否收到主机SPI发来的数据 { SPI_Receive=0; // 清0主单片机SPI端口收到数据标志位 SPDAT=SPI_buffer; // 将收到数据送SPDAT,准备下一次通讯时发回 } #endif } } void SPI_ISR(void) interrupt 9 { SPSTAT=0xC0; // 清0标志位SPIF和WCOL SPI_buffer=SPDAT; // 保存收到的数据 SPI_Receive=1; // 设置SPI端口收到数据标志 }
相关文章推荐
- spi 协议硬件分析以及在linux上的实现分析
- 通过API实现C#对硬件的控制(一)
- 用GPIO模拟SPI协议的实现[转]
- C# 实现对硬件的控制
- 多功能;由各自独立的专用硬件的实现。
- 通过API实现C#对硬件的控制(二)
- SkyEye硬件模拟平台:硬件仿真实现之六
- "阻塞--中断"驱动模型在i2c在子系统、uart驱动、spi子系统中的实现
- 关于RSA硬件算法的实现问题!
- Dubbo源代码实现四:Dubbo中的扩展点与SPI
- C# 实现对硬件的控制
- Android网络开发回顾之旅 ① 在Android手机集成使用MQTT协议 ,实现搞掂移动控制硬件端。(附带Demo)
- Jboss集群(五)--F5硬件负载均衡器双击热备 + Jboss集群终极实现
- 如何在LINUX下实现硬件的自动检测(上)
- SPI总线介绍和verilog实现
- 通过API实现C#对硬件的控制(二)
- 基于SPI的数据报过滤原理与实现
- 如何在LINUX下实现硬件的自动检测(上)
- ActiveX(ocx) + DLL(wosa) + JS:实现BS硬件调用框架(二)
- 2. Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现