51单片机模拟spi串行接口程序
- 格式:doc
- 大小:48.50 KB
- 文档页数:8
单片机模拟SPI程序单片机模拟SPI程序分类: C/C++IO口模拟SPI通信C51程序 /************************** 文件所用资源1.端口:P0.4,P0.5,P0.6,P0.72.调用delay_ms函数**************************//*************************模拟SPI接口I/O定义*************************/sbit spi_cs=P0^1;sbit spi_di=P0^2;sbit spi_clk=P0^3;sbit spi_do=P0^4;/*******************************向SPI器件写入一个字节数据*******************************/void spi_write(unsigned char spi_dat){unsigned char i;spi_cs=0;for (i=0;i<8;i++){spi_clk=0;if((spi_dat & 0x80)==0x80)spi_di=1;else spi_di=0;spi_clk=1;spi_dat=(spi_dat<<1);}spi_cs=1;}/******************************** 从SPI器件读出一个字节数据********************************/ unsigned char spi_read(){unsigned char i,spi_dat;spi_cs=0;for (i=0;i<8;i++){spi_clk=0;spi_dat=(spi_dat<<1);spi_clk=1;if(spi_do==1)spi_dat|=0x01; else spi_dat&=~0x01;}spi_cs=1;return spi_dat;}其实光模拟来说,就时序问题,读取和写入一个字节的时序。
51 单片机模拟spi 串行接口程序51 单片机模拟spi 串行接口程序,在keilc51 下编写sbit CS=P3A5;sbit CLK= P"5;sbit DataI=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPI_TransferByte(unsigned char val){unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // write if(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5;sbit DataI=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPI_TransferByte(unsigned char val){unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // write if(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5; sbit DataI=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPI_TransferByte(unsigned char val) { unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // writeif(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5;sbit DataI=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPI_TransferByte(unsigned char val) { unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // writeif(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5;sbit Datal=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPl_TransferByte(unsigned char val) unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // writeif(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5;sbit Datal=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPl_TransferByte(unsigned char val) { unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // write if(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5;sbit Datal=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPl_TransferByte(unsigned char val) { unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;Datal=0; // writeif(val&0x80) Datal=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}sbit CLK= P1A5;sbit Datal=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPl_TransferByte(unsigned char val) { unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;Datal=0; // writeif(val&0x80) Datal=1;val<<=1;CLK=1;if(DataO)val|=1; // readCLK=0;return val;}sbit CLK= P1A5;sbit Datal=P1A7;sbit DataO=P1A6;#define SD_Disable() CS=1 // 片选关#define SD_Enable() CS=0 // 片选开unsigned char SPl_TransferByte(unsigned char val) { unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;Datal=0; // writeif(val&0x80) Datal=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;。
SPI总线在51系列单片机系统中的实现(一)摘要:MCS51系列、MCS96系列等单片机由于都不带SPI串行总线接口而限制了其在SPI总线接口器件的使用。
文中介绍了SPI串行总线的特征和时序,并以串行E2PROM为例,给出了在51系列单片机上利用I/O口线实现SPI串行总线接口的方法和软件设计程序。
关键词:单片机SPI串行总线总线接口1引言SPI(SerialPeripheralInterface--串行外设接口)总线系统是一种同步串行外设接口,它可以使MCU与各种外围设备以串行方式进行通信以交换信息。
外围设置FLASHRAM、网络控制器、LCD显示驱动器、A/D转换器和MCU等。
SPI总线系统可直接与各个厂家生产的多种标准外围器件直接接口,该接口一般使用4条线:串行时钟线(SCK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOST和低电平有效的从机选择线SS(有的SPI接口芯片带有中断信号线INT或INT、有的SPI接口芯片没有主机输出/从机输入数据线MOSI)。
由于SPI系统总线一共只需3~4位数据线和控制即可实现与具有SPI总线接口功能的各种I/O器件进行接口,而扩展并行总线则需要8根数据线、8~16位地址线、2~3位控制线,因此,采用SPI总线接口可以简化电路设计,节省很多常规电路中的接口器件和I/O口线,提高设计的可靠性。
由此可见,在MCS51系列等不具有SPI接口的单片机组成的智能仪器和工业测控系统中,当传输速度要求不是太高时,使用SPI总线可以增加应用系统接口器件的种类,提高应用系统的性能。
2SPI总线的组成利用SPI总线可在软件的控制下构成各种系统。
如1个主MCU和几个从MCU、几个从MCU相互连接构成多主机系统(分布式系统)、1个主MCU和1个或几个从I/O设备所构成的各种系统等。
在大多数应用场合,可使用1个MCU作为控机来控制数据,并向1个或几个从外围器件传送该数据。
51模拟SPI接口在MCS51系列单片机中的实现方法对于不带SPI串行总线接口的MCS51系列单片机来说,可以使用软件来模拟SPI的操作,包括串行时钟、数据输入和数据输出。
对于不同的串行接口外围芯片,它们的时钟时序是不同的。
对于在SCK的上升沿输入(接收)数据和在下降沿输出(发送)数据的器件,一般应将其串行时钟输出口P1.1的初始状态设置为1,而在允许接口后再置P1.1为0。
这样,MCU 在输出1位SCK时钟的同时,将使接口芯片串行左移,从而输出1位数据至MCS51单片机的P1.3口(模拟MCU的MISO线),此后再置P1.1为1,使MCS51系列单片机从P1.0(模拟MCU的MOSI线)输出1位数据(先为高位)至串行接口芯片。
至此,模拟1位数据输入输出便宣告完成。
此后再置P1.1为0,模拟下1位数据的输入输出……,依此循环8次,即可完成1次通过SPI总线传输8位数据的操作。
对于在SCK的下降沿输入数据和上升沿输出数据的器件,则应取串行时钟输出的初始状态为0,即在接口芯片允许时,先置P1.1为1,以便外围接口芯片输出1位数据(MCU接收1位数据),之后再置时钟为0,使外围接口芯片接收1位数据(MCU发送1位数据),从而完成1位数据的传送。
图2所示为MCS51系列单片机与存储器X25F008(E2PROM)的硬件连接图,有关X25F008的详细资料可参考有关文献〔1〕。
图2中,P1.0模拟MCU的数据输出端(MOSI),P1.1模拟SPI的SCK输出端,P1.2模拟SPI的从机选择端,P1.3模拟SPI的数据输入端(MISO)。
下面介绍用MCS51单片机的汇编语言模拟SPI串行输入、串行输出和串行输入/输出的3个子程序。
实际上,这些子程序也适用于在串行时钟的上升沿输入和下降沿输出的其它各种串行外围接口芯片(如A/D转换芯片、网络控制器芯片、LED显示驱动芯片等)。
对于下降沿输入、上升沿输出的各种串行外围接口芯片,只要改变P1.1的输出电平顺序,即先置P1.1为低电平,之后再次置P1.1为高电平,再置P1.1为低电平……,则这些子程序也同样适用。
51单片机教程:单片机串行口通信程序设计1.串行口方式0应用编程 8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就能扩展一个并行口。
单片机串行口通信程序设计硬件连接图例:用8051单片机串行口外接CD4094扩展8位并行输出口,如图所示,8位并行口的各位都接一个发光二极管,要求发光管呈流水灯状态。
串行口方式0的数据传送可采用中断方式,也可采用查询方式,无论哪种方式,都要借助于TI或RI标志。
串行发送时,能靠TI置位(发完一帧数据后)引起中断申请,在中断服务程序中发送下一帧数据,或者通过查询TI的状态,只要TI为0就继续查询,TI为1就结束查询,发送下一帧数据。
在串行接收时,则由RI引起中断或对RI查询来确定何时接收下一帧数据。
无论采用什么方式,在开始通信之前,都要先对控制寄存器SCON进行初始化。
在方式0中将,将00H送SCON就能了。
单片机串行口通信程序设计列子ORG 2000HSTART: MOV SCON,#00H ;置串行口工作方式0MOV A,#80H ;最高位灯先亮CLR P1.0 ;关闭并行输出(避象传输过程中,各LED的暗红现象) OUT0: MOV SBUF,A ;开始串行输出OUT1: JNB TI,OUT1 ;输出完否CLR TI ;完了,清TI标志,以备下次发送SETB P1.0 ;打开并行口输出ACALL DELAY ;延时一段时间RR A ;循环右移CLR P1.0 ;关闭并行输出JMP OUT0 ;循环说明:DELAY延时子程序能用前面我们讲P1口流水灯时用的延时子程序,这里就不给出了。
二、串行口异步通信org 0000HAJMP STARTORG 30HSTART:mov SP,#5fh ;mov TMOD,#20h ;T1: 工作模式2mov PCON,#80h ;SMOD=1mov TH1,#0FDH ;初始化波特率(参见表)mov SCON,#50h ;Standard UART settingsMOV R0,#0AAH ;准备送出的数SETB REN ;允许接收SETB TR1 ;T1开始工作WAIT:MOV A,R0CPL AMOV R0,AMOV SBUF,ALCALL DELAYJBC TI,WAIT1 ;如果TI等于1,则清TI并转WAIT1AJMP WAITWAIT1: JBC RI,READ ;如果RI等于1,则清RI并转READAJMP WAIT1READ:MOV A,SBUF ;将取得的数送P1口MOV P1,ALJMP WAITDELAY: ;延时子程序MOV R7,#0ffHDJNZ R7,$RETEND将程序编译通过,写入芯片,插入实验板,用通读电缆将实验板与主机的串行口相连就能实验了。
论坛新老朋友们。
祝大家新年快乐。
在新的一年开始的时候,给大家一点小小的玩意。
工程师经常碰到需要多个串口通信的时候,而低端单片机大多只有一个串行口,甚至没有串口。
这时候无论是选择高端芯片,还是更改系统设计都是比较麻烦的事。
我把以前搞的用普通I/O口模拟串行口通讯的程序拿出来,供大家参考,希望各位兄弟轻点拍砖。
基本原理:我们模拟的是串行口方式1.就是最普通的方式。
一个起始位、8个数据位、一个停止位。
模拟串行口最关键的就是要计算出每个位的时间。
以波特率9600为例,每秒发9 600个位,每个位就是1/9600秒,约104个微秒。
我们需要做一个精确的延时,延时时间+对IO口置位的时间=104微秒。
起始位是低状态,再延时一个位的时间。
停止位是高状态,也是一个位的时间。
数据位是8个位,发送时低位先发出去,接收时先接低位。
了解这些以后,做个IO模拟串口的程序,就是很容易的事。
我们开始。
先上简单原理图:就一个MAX232芯片,没什么好说的,一看就明白。
使用单片机普通I/ O口,232数据输入端使用51单片机P3.2口(外部中断1口,接到普通口上也可以,模拟中断方式的串行口会有用。
呵呵)。
数据输出为P0.4(随便哪个口都行)。
下面这个程序,您只需吧P0.4 和P3.2 当成串口直接使用即可,经过测试完全没有问题.2、底层函数代码如下:sbit TXD1 = P0^4; //定义模拟输出脚sbit RXD1 = P3^2; //定义模拟输入脚bdata unsigned char SBUF1; //定义一个位操作变量sbit SBUF1_bit0 = SBUF1^0;sbit SBUF1_bit1 = SBUF1^1;sbit SBUF1_bit2 = SBUF1^2;sbit SBUF1_bit3 = SBUF1^3;sbit SBUF1_bit4 = SBUF1^4;sbit SBUF1_bit5 = SBUF1^5;sbit SBUF1_bit6 = SBUF1^6;sbit SBUF1_bit7 = SBUF1^7;void delay_bps() {unsigned char i; for (i = 0; i < 29; i++); _nop_(); _nop_();} //波特率9600 模拟一个9600波特率unsigned char getchar2() //模拟接收一个字节数据{while (RXD1);_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); delay_bps();SBUF1_bit0 = RXD1; //0delay_bps();SBUF1_bit1 = RXD1; //1delay_bps();SBUF1_bit2 = RXD1; //2delay_bps();SBUF1_bit3 = RXD1; //3delay_bps();SBUF1_bit4 = RXD1; //4delay_bps();SBUF1_bit5 = RXD1; //5delay_bps();SBUF1_bit6 = RXD1; //6delay_bps();SBUF1_bit7 = RXD1; //7delay_bps();return(SBUF1) ; //返回读取的数据}void putchar2(unsigned char input) //模拟发送一个字节数据{SBUF1 = input;TXD1 = 0; //起始位delay_bps();TXD1 = SBUF1_bit0; //0delay_bps();TXD1 = SBUF1_bit1; //1delay_bps();TXD1 = SBUF1_bit2; //2delay_bps();TXD1 = SBUF1_bit3; //3delay_bps();TXD1 = SBUF1_bit4; //4delay_bps();TXD1 = SBUF1_bit5; //5delay_bps();TXD1 = SBUF1_bit6; //6delay_bps();TXD1 = SBUF1_bit7; //7delay_bps();TXD1 = 1; //停止位delay_bps();}3、实现串行通讯。
基于单片机I/O口模拟的SPI串行通信实现【摘要】基于单片机或ARM芯片的普通I/O口,模拟实现SPI串行通信。
模拟SPI通信需严格时钟时序,只有当主器件模拟的SPI时序与从器件的SPI时序完全一致时,才能实现SPI通信的正常数据交换。
【关键词】I/O口;SPI时序;主器件;从器件1.引言SPI(SeIial Peripheral Interfa即串行外围设备接口)总线技术是一种高效率的串行接口技术,主要用于扩展外设和进行数据交换。
在许多单片机中,已经作为一种标准配置。
但某些应用非常广泛的单片机并不带标准SPI接口,这样就限制了在这些系统中使用带SPI接口的器件。
解决该问题的方法是使用单片机的普通I/O口通过软件模拟的方式实现SPI串口通信,以满足应用需求。
此外,采用标准的SPI接口有很多局限性,在设备外围开发和扩展增加负担,而通过I/O口模拟实现SPI通信将不受这些限制,可轻松实现其外围开发和扩展,灵活性更大;通过I/O口模拟SPI通信,其通用性和可移植性强,实现简单、方便。
2.SPI总线概述SPI通信的总线形式一般采用4线制,即为使能控制线SN、始终控制线SCLK、主出从入线MOSI和主入从出线MISO。
可实现一个主控制器挂接多个从控制器,如图1所示,为SPI总线框图。
使能控制线SN完成对从控制器的片选,当需要与某个控制通信时,将SN 置于打开(高或者低,根据不同芯片分别对待)状态,使从控制器处于可通信状态,同时时钟控制线SCLK用于控制SPI通信的时序,该时序需与从控制器的SPI时序保持完全一致,这样才能保证SPI通信的实现。
主出从入线MOSI为SPI 串口通信数据输出线,主入从出线MISO为SPI串口通信数据输入线。
当主控制器MCU只与一个从控制器通信或所选从控制器无使能控制端时,使能控制线SN可不用,即3线制SPI通信,也可实现模拟SPI通信。
3.SPI通信时序控制相对于标准的SPI通信接口,通过I/O口模拟的SPI通信,其模拟时序要求很严格,即主控制器模拟的SPI时序必须与从控制器的SPI通信时序保持一致,否则会导致在通信时出现接收不到数据或是接收数据错误的情况。
单片机IO口模拟SPI四种模式的程序单片机IO口模拟SPI四种模式的程序#include "iom8535v.h"#define _CPOL 1#define _CPHA 0#define SCK_IO DDRA|=0X01#define MOSI_IO DDRA|=0X02#define MISO_IO DDRA&=0XFB#define SSEL_IO DDRA|=0X08#define SCK_D(X) (X?(PORTA|=0X01):(PORTA&=0XFE)) #define MOSI_D(X) (X?(PORTA|=0X02):(PORTA&=0XFD)) #define SSEL_D(X) (X?(PORTA|=0X08):(PORTA&=0XF7))#define MISO_I() (PINA&0X04)void delay(){unsigned char m,n;for(n=0;n<5;n++);for(m=0;m<100;m++);}/************************************************ 端口方向配置与输出初始化************************************************/ void SPI_Init(void){SCK_IO ;MOSI_IO ;MISO_IO ;SSEL_IO ;SSEL_D(1);MOSI_D(1);#if _CPOL==0SCK_D(0);#elseSCK_D(1);#endif}/**********************************************模式零写数据***********************************************/ #if _CPOL==0&&_CPHA==0 //MODE 0 0 void SPI_Send_Dat(unsigned char dat){unsigned char n;for(n=0;n<8;n++){SCK_D(0);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(1);}SCK_D(0);}/********************************************* 模式零读数据*********************************************/ unsigned char SPI_Receiver_Dat(void){unsigned char n ,dat,bit_t;for(n=0;n<8;n++)SCK_D(0);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(1);}SCK_D(0);return dat;}#endif/********************************************** 模式二写数据***********************************************/ #if _CPOL==1&&_CPHA==0 //MODE 1 0 void SPI_Send_Dat(unsigned char dat){unsigned char n;for(n=0;n<8;n++){SCK_D(1);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(0);}SCK_D(1);}/********************************************* 模式二读数据*********************************************/ unsigned char SPI_Receiver_Dat(void)unsigned char n ,dat,bit_t;for(n=0;n<8;n++){SCK_D(1);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(0);}SCK_D(1);return dat;}#endif/********************************************* 模式一写数据*********************************************/ #if _CPOL==0&&_CPHA==1 //MODE 0 1 void SPI_Send_Dat(unsigned char dat){unsigned char n;SCK_D(0);for(n=0;n<8;n++){SCK_D(1);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(0);}}/********************************************* 模式一读数据*********************************************/ unsigned char SPI_Receiver_Dat(void){unsigned char n ,dat,bit_t;for(n=0;n<8;n++){SCK_D(1);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(0);}SCK_D(0);return dat;}#endif//////////////////////////////////////////////////////////////////////////////////////////////////////////////#if _CPOL==1&&_CPHA==1 //MODE 1 1void SPI_Send_Dat(unsigned char dat){unsigned char n;SCK_D(1);for(n=0;n<8;n++){SCK_D(0);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(1);}}/************************************模式三读数据************************************/unsigned char SPI_Receiver_Dat(void){unsigned char n ,dat,bit_t;SCK_D(0);for(n=0;n<8;n++){ SCK_D(0);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(1);}SCK_D(1);return dat;}#endif/**************************************************************************/ void main() {SPI_Init();DDRB = 0XFF;//#if _CPOL//SCK_D(0);//#endifwhile(1){//SSEL_D(0);//SPI_Send_Dat(0x01);//SPI_Send_Dat(0x31);//SSEL_D(1);SSEL_D(0);SPI_Send_Dat(0x81); PORTB =SPI_Receiver_Dat(); SSEL_D(1);//delay();}}。