运用4个普通IO口模拟SPI程序等
- 格式:pdf
- 大小:200.42 KB
- 文档页数:32
4根IO口线驱动1602(带PWM调光)呵呵,不用我说你们也知道为什么只需要4根线:因为咱用了74hc595啊!因为74HC595最近我手里一抓一大把。
但是STC的单片机IO口紧缺。
就算使用4线驱动模式也要8个IO(还要算上背光PWM)。
这一次我几乎做到了他的一半。
如果不用PWM的话。
大概只需要3个IO,如果需要PWM就四个罗。
MCU当然是老掉牙的死特惨89C52罗~画原理图实在是不方便。
就不画了。
另外求酷~也可以在595后面级联类似三极管开关……继电器之类的玩意。
当然友情提醒,别超过4个595.否则速度会慢的可怕。
我现在1个595.写1602都可以丢掉延时函数了。
这一次硬件设计的比较简单,但是IO全反了。
所以需要占用额外的CPU时间修正,但是毕竟方便洞洞板嘛。
还有大家别看到我给A和B赋了好几次值而去“优化”代码。
如果您“优化”的话,那么就根本驱动不起来,因为51的加法减法乘除都要经过ACC和B,如果不去重新赋值的话,那么就会发生改变的现象。
不过我这种位寻址软件修正可比那种xx=xx & xx的效率高多了。
如果我这么写的话。
恐怕刷一个屏幕没1秒下不来啊。
12T的51就这个速度……不过这一次焊板子实在是太仓促了。
对比度电位器焊在液晶下面,结果初始化成功了显示两排方块。
晕了半天。
调试半天还是没用。
后来捅了一下背面就好了……晕……!上代码:#include <stc89c5x.h>//STC89C52//串行驱动1602,powered by 595#define LCD1602_BACKLIGHT P1_3//背光#define LCD1602_SDA P1_0//数据输入#define LCD1602_SCK P1_1//移位时钟,SHCP,11pin#define LCD1602_SCL P1_2//锁存时钟,STCP,12pin/** 硬件连接:* 74HC595 Q7 - 1602 RS* GND - 1602 RW(595没有输入功能,所以判定忙只能靠延时,另外就是MCU的速度比较的慢。
使用MCU的GPIO模拟SPI在树莓派等单片机(MCU)上,可以使用GPIO模拟SPI(串行外设接口)来与其他设备进行通信。
SPI是一种同步串行数据传输协议,通常用于连接MCU和传感器、显示器、存储器等外设。
以下是使用MCU的GPIO模拟SPI的详细步骤。
1.了解SPI的基本原理:SPI使用四根信号线进行通信,包括时钟(SCLK)、主机输出从机输入(MOSI)、主机输入从机输出(MISO)和片选(SS)。
-SCLK:时钟信号,由主机产生,用于同步数据传输。
-MOSI:主机输出从机输入,主机将数据发送到从机。
-MISO:主机输入从机输出,从机将数据发送到主机。
-SS:片选信号,用于选择从机。
2.确定所需GPIO引脚:根据所连接的设备的要求,选择合适的GPIO引脚作为SCLK、MOSI、MISO和SS。
3. 配置GPIO引脚:在MCU上,使用相应的编程语言和库函数来配置GPIO引脚。
例如,在树莓派上使用Python编程,可以使用RPi.GPIO库进行配置。
4.编写SPI传输函数:编写一个函数来模拟SPI传输。
该函数应包括以下步骤:a.设置SS为低电平,选中从机设备。
b.发送数据比特串:逐位发送MOSI数据,同时接收并保存MISO数据。
c.设置SS为高电平,取消从机设备的选中。
假设我们要发送8位数据,可以使用以下Python代码实现SPI传输函数:```pythonimport RPi.GPIO as GPIOdef spi_transfer(data):GPIO.output(SS, GPIO.LOW) # 选中从机received_data = 0for bit in range(7, -1, -1): # 逐位传输数据#发送MOSI数据GPIO.output(MOSI, (data >> bit) & 0x01)#接收并保存MISO数据received_bit = GPIO.input(MISO)received_data = (received_data << 1) , received_bit#在SCLK上升沿发送和接收数据GPIO.output(SCLK, GPIO.HIGH)GPIO.output(SCLK, GPIO.LOW)GPIO.output(SS, GPIO.HIGH) # 取消从机选中return received_data```5. 通过调用SPI传输函数与从机通信:在应用程序中,根据需要调用SPI传输函数。
一SPI协议概括SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。
是Motorola首先在其MC68HCXX系列处理器上定义的。
SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,比如AT91RM9200.SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。
也是所有基于SPI的设备共有的,它们是SDI (数据输入),SDO(数据输出),SCK(时钟),CS(片选)。
(1)SDO –主设备数据输出,从设备数据输入(2)SDI –主设备数据输入,从设备数据输出(3)SCLK –时钟信号,由主设备产生(4)CS –从设备使能信号,由主设备控制其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效。
这就允许在同一总线上连接多个SPI设备成为可能。
接下来就负责通讯的3根线了。
通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。
这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。
数据输出通过SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。
完成一位数据传输,输入也使用同样原理。
这样,在至少8次时钟信号的改变(上沿和下沿为一次),就可以完成8位数据的传输。
要注意的是,SCK信号线只由主设备控制,从设备不能控制信号线。
同样,在一个基于SPI的设备中,至少有一个主控设备。
怎样使用IO口模拟SPI时序访问W5100 2008-2-23 23:31:48摘自浩然电子:http:很多客户为了简化硬件设计,在对速度要求不高的情况下,常常采用SPI 总线访问W5100。
这里根据浩然电子EVB-W5100/MCS51评估板,给出一个用MCS51的I/O口模拟SPI总线访问的C程序例子。
该程序经过修改可以移植到任何单片机系统中。
/*************定义SPI的引脚端口**************/sbit SCS =P3^3;/*定义SPI的片选信号端口*/sbit SCLK =P2^3;/*定义SPI的时钟信号端口*/sbitMISO =P2^6;/*定义SPI的MISO端口*/sbit MOSI =P2^4;/*定义SPI的MOSI端口*/#define SET_SCS SCS=1;#define RESET_SCS SCS=0;#define SET_SCLK SCLK=1;#define RESET_SCLK SCLK=0;#define SET_MOSI MOSI=1;#defineRESET_MOSI MOSI=0;/***************************************************************** ***IO_Config主要是对IO口进行初始化设置根据不同的MCU添加相应的代码,实现下面注释部分的功能***************************************************************** ***/voidIO_Config (void ){/*定义SCS口为输出,初始化为高电平*/SET_SCS/*定义SCLK口为输出,初始化为低电平*/RESET_SCLK/*定义CPU的MOSI端口为输出, MISO端口为输入*/}/****************************************************************** **通过SPI总线输出一个字节***************************************************************** ***/void SPI_Out (unsigned chardat ){unsigned chari;for ( i = 0; i < 8; i++){if ( dat & 0x80 )SET_MOSIelseRESET_MOSISET_SCLK /*时钟上升*/dat <<= 1;RESET_SCLK /*时钟下降*/}}/***************************************************************** ***通过SPI向W5100写入数据输入参数:写入地址addr,写入的数据dat无返回参数***************************************************************** ***/voidWrite_W5100_SPI (unsigned intaddr,unsigned chardat ){RESET_SCS/* SPI的片选置低*//*输出的第一个字节为写命令*/SPI_Out ( 0xf0 );/*写命令*//*输出的第二个字节为地址高8位*/SPI_Out ( addr / 256 );/*地址高8位*//*输出的第三个字节为地址低8位*/SPI_Out ( addr );/*地址低8位*//*输出的第四个字节为写入的数据*/SPI_Out ( dat );SET_SCS /* SPI的片选置高*/}/****************************************************************** **通过SPI读取W5100的数据输入参数:读取地址addr,返回参数:读取的数据***************************************************************** ***/unsigned charRead_W5100_SPI (unsigned intaddr ){unsigned chari, j;RESET_SCS /* SPI的片选置低*//*输出的第一个字节为写命令*/SPI_Out ( 0x0f );/*读命令*//*输出的第二个字节为地址高8位*/SPI_Out ( addr / 256 );/*地址高8位*//*输出的第三个字节为地址低8位*/SPI_Out ( addr );/*地址低8位*//*输出一个空字节,读取一个字节的数据*/j=0;for( i = 0; i < 8; i++ ){ SET_SCLK/*时钟上升*/j <<= 1;if( MISO )j |= 0x01;RESET_SCLK /*时钟下降*/} SET_SCS/* SPI的片选置高电平*/returnj;}先调用IO_Config()函数对IO口进行初始化设置。
时钟相位(CPHA)和时钟极性(CPOL)的不同组合使得SPI传输有了4种方式如果CPOL =0,SCK 引脚在空闲状态保持低电平;如果CPOL =1,SCK 引脚在空闲状态保持高电平时序图如下://IO端口定义#define SPI_SCK PC0#define SPI_MOSI PC1#define SPI_MISO PC2#define SPI_DDR DDRC#define SPI_PORT PROTC#define SPI_PIN PINC//端口操作符定义#define SCK_SET SPI_PORT|=_BV(SPI_SCK)#define SCK_CLR SPI_PORT&=~_BV(SPI-SCK)#define MOSI_SET SPI_PORT|=_BV(SPI_MOSI)#define MOSI_CLR SPI_PORT&=~_BV(SPI_MOSI)#define MISO_PIN PINC&_BV(SPI_MISO)#define DELAY_BUS //如需要延时,用延时函数替代此符号//模式1:CPOL=1 CPHA=1void spi_init(void){SCK_SET;SPI_DDR|=_BV(SPI_MOSI)|_BV(SPI_SCK);}uint8_t spi_readwrite_byte(uint8_t data){uint8_t i,ret=0;for(i=0;i<8;i++){//下降沿模拟if(data&0x80)//设置输出MOSI_SET;elseMOSI_CLR;SCK_CRL;//SCK产生下降沿DELAY_BUS;//上升沿模拟ret<<=1;if(MISO_PIN)//读数据ret|=1;SCK_SET; //SCK产生上升沿data<<=1;DELAY_BUS;}return ret;}//模式2:CPOL=0 CPHA=1void spi_init(void){SCK_CLR;SPI_DDR|=_BV(SPI_MOSI)|_BV(SPI_SCK);}uint8_t spi_readwrite_byte(uint8_t data) {uint8_t i,ret=0;for(i=0;i<8;i++){//上升沿模拟if(data&0x80)//设置输出MOSI_SET;elseMOSI_CLR;SCK_SET;//SCK产生上升沿DELAY_BUS;//下降沿模拟ret<<=1;if(MISO_PIN)//读数据ret|=1;SCK_CLR; //SCK产生下降沿data<<=1;DELAY_BUS;}return ret;}//模式3:CPOL=1 CPHA=0void spi_init(void){SCK_SET;SPI_DDR|=_BV(SPI_MOSI)|_BV(SPI_SCK);}uint8_t spi_readwrite_byte(uint8_t data) {uint8_t i,ret=0;//设置好输出口if(data&0x80)MOSI_SET;elseMOSI_CLR;for(i=0;i<8;i++){DELAY_BUS;//下降沿模拟ret<<=1;if(MISO_PIN)//读数据ret|=1;SCK_CRL;//SCK产生下降沿DELAY_BUS;//上升沿模拟data<<=1;if(data&0x80)//设置输出MOSI_SET;elseMOSI_CLR;SCK_SET; //SCK产生上升沿}return ret;}//模式4:CPOL=0 CPHA=0void spi_init(void){SCK_CLR;SPI_DDR|=_BV(SPI_MOSI)|_BV(SPI_SCK);}uint8_t spi_readwrite_byte(uint8_t data) {uint8_t i,ret=0;//设置好输出口if(data&0x80)MOSI_SET;elseMOSI_CLR;for(i=0;i<8;i++){DELAY_BUS;//上升沿模拟ret<<=1;if(MISO_PIN)//读数据ret|=1;SCK_SET;//SCK产生上升沿DELAY_BUS;//下降沿模拟data<<=1;if(data&0x80)//设置输出 MOSI_SET;elseMOSI_CLR;SCK_CLR; //SCK产生下降沿 }return ret;}。
几种常用的模拟SPI读写一体化模块(C51)几种常用的模拟SPI读写一体化模块(C51)原文:说明:SPI接口有一个特点,即在时钟SCK的上升沿打入数据MOSI,在下降沿读入数据MISO.片选信号CS有正负区别.在硬件上MOSI与MISO是可以短路变为SIO可读写IO的.故SPI可为(不包括CS)三线(SCK,MOSI,MISO)协议,两线(SCK,SIO)协议再者,SPI一般为双向同时高速收发数据的,方向由时钟SCK的跳变沿决定。
根据以上所述,模拟SPI读写模块编制成为一体化模块是必要的。
而且调用规则只需注意读数据时要写入0xff即可。
非常方便好用。
例如:res = SpiReadWrite(val);//模块写SpiReadWrite(0xff);//模块读对于具体器件,由于涉及到命令、地址及数据等,故一个完整的SPI读或写操作可能需要几个模拟SPI读写一体化模块来完成。
所以一般完整的SPI读或写操作需以下函数组合完成void SpiOpen(void); //打开片选 CS=0或CS=1void SpiClose(void); //关闭片选 CS=1或CS=0unsigned char SpiReadWrite(val); //模拟SPI读写一体化模块void SpiWriteEnable(void); //使能写操作void SpiWriteD ISA ble(void); //禁止写操作unsigned char SpiReadStatus(void); //读状态void SpiWriteStatus(unsigned char val); //写状态void SpiWriteWait(void); //等待写入完成void SpiWriteByte(unsigned int addr, unsigned char val);//写一个字节void SpiWriteWord(unsigned char addr, unsigned int val);//写一个字unsigned char SpiReadByte(unsigned int addr); //读一个字节unsigned int SpiReadWord(unsigned char addr); //读一个字/*----------------------------------------------------------------------------/*-----------------------------------------------例:X5045模拟SPI读写一体化模块PTR905模拟SPI读写一体化模块------------------------------------------------*unsigned char SpiReadWrite(unsigned char val){unsigned char i;ACC = val;for (i = 8; i > 0; i --){CY = MISO;//取数据SO_rlca_();//存数据ACC.0读数据ACC.7同时进行MOSI = CY;//送数据SISCK = 1;//上升沿打入数据_nop_();//延时SCK = 0;//下降沿读入数据}return ACC;}/*----------------------------------------------- 例:X5045模拟SPI读写一体化模块ISD4004模拟SPI读写一体化模块------------------------------------------------* unsigned char SpiReadWrite(unsigned char val) {unsigned char i;ACC = val;for (i = 8; i > 0; i --){SCK = 0;//下降沿读入数据_nop_();//延时CY = MISO;//取数据SO_rlca_();//存数据ACC.0读数据ACC.7同时进行MOSI = CY;//送数据SI_nop_();//延时SCK = 1;//上升沿打入数据MOSI = 1;//释放总线SI}return ACC;}/*----------------------------------------------- 例:AT93C46模拟SPI读写模块------------------------------------------------* sbit ACC_7 = ACC^7;unsigned char SpiReadWrite(unsigned char val) {unsigned char i;ACC = val;for (i = 8; i > 0; i --){CY = ACC_7;//读数据ACC.7MOSI = CY;//送数据SISCK = 1;//上升沿打入数据CY = MISO;//取数据SO_rlca_();//存数据ACC.0SCK = 0;//下降沿}return ACC;}。
IO口模拟spi主从机通讯例程下面这两幅图是,关于SPI数据读取或发送的时序图。
1、主机io口模拟spi通讯例程//**spi io 口初始化**//void SPI_init(void){gpio_configure_fpin(SPI_MISO, IO_TYPE_INPUT);//配置成输入模式gpio_configure_fpin(SPI_MOSI, IO_OUTPUT_1);//配置成输出模式gpio_configure_fpin(SPI_SCK, IO_OUTPUT_1); //配置成输出模式gpio_configure_fpin(SPI_CS, IO_OUTPUT_1); //配置成输出模式clr_spi_GPIO(SPI_SCK);//拉低SPI_SCKset_spi_GPIO(SPI_CS);//拉高SPI_SCKclr_spi_GPIO(SPI_MOSI);//拉低SPI_MOSI}//**主机spi读取一字节api**//unsigned char SPI_ReadByte(void){unsigned char i,rByte=0;clr_spi_GPIO(SPI_CS);for(i=0;i<8;i++){clr_spi_GPIO(SPI_SCK);//clr_spi_sck;delay_us(3);rByte<<=1;if(MISO_is_status())////M16 MISO---PB6rByte|=1;set_spi_GPIO(SPI_SCK);//set_spi_sck;delay_us(3);}clr_spi_GPIO(SPI_SCK);set_spi_GPIO(SPI_CS);return rByte;}//** 读取miso 的电平**//char MISO_is_status(void){if(red_spi_GPIO(SPI_MISO))//return 1;elsereturn 0;}//**主机spi写入一字节api**//void SPI_WriteByte(unsigned char wByte){unsigned char i;clr_spi_GPIO(SPI_CS);for(i=0;i<8;i++){clr_spi_GPIO(SPI_SCK);//delay_us(3);//if(wByte&0x80){set_spi_GPIO(SPI_MOSI);//}else{clr_spi_GPIO(SPI_MOSI);//}wByte=wByte<<1;set_spi_GPIO(SPI_SCK);//set_spi_sck;delay_us(3);//}clr_spi_GPIO(SPI_SCK);set_spi_GPIO(SPI_CS);}////////////////////////////////////////////////////////////////////////////////////注意,我写的主从机的io口对接如下主机io 从机ioSPI_MISO ------------------------- SPI_MISOSPI_MOSI --------------------------- SPI_MOSISPI_SCK --------------------------- SPI_SCKSPI_CS -------------------------- SPI_CS可能有的人对上面的io口对接的方式感到奇怪,请仔细看我对这几个io口做的初始化设置就可以明白。
IO口模拟SPI接口//头文件#include#include/*********************************************模拟SPI接口I/O定义*********************************************/sbit CS =P3^2; //片选信号 (输入)sbit SCK =P3^3; //时钟信号 (输入)sbit MISO=P3^4; //主站输入从站输出 (输出)sbit MOSI=P3^5; //主站输出从站输入 (输入)#define SET_CS() CS=1 //片选信号置高#define RESET_CS() CS=0 //片选信号置低#define SET_SCK() SCK=1 //时钟信号置高#define RESET_SCK() SCK=0 //时钟信号置低//自定义变量unsigned char spi_flag=0,SPI_Data=0;//自定义函数extern void Usart_Send(unsigned char Data);/************************************************************** **********程序描述:系统初始化程序*************************************************************** ****************/void System_Init(){//串口参数初始化SCON = 0x50; //REN=1允许串行接受状态,串口工作模式1 TMOD|= 0x20; //定时器工作方式2PCON|= 0x80;TH1 = 0xF3; //baud*2 4800、数据位8、停止位1、效验位无(12M)TL1 = 0xF3;TR1 = 1; //允许定时器1计数ES = 1; //开串口中断*///定时器0初始化TMOD|= 0x01; //定时器工作方式1TH0 = 0xFC; //1msTL0 = 0x18;TR0 = 1; //允许定时器0计数ET0 = 1; //开定时器0中断IP=0x03; //设置定时器0中断高优先级//IT1=0; //低电平触发IT1=1; //下降沿触发//EX1=1; //外部中断1允许EA=1; //开总中断}/************************************************************** **********程序描述:模拟SPI通信主程序*************************************************************** ****************/main(){System_Init();while(1){/*if(MOSI==1)Usart_Send(0x01);elseUsart_Send(0x00);*/}}/************************************************************** **********程序描述:定时器0中断程序*************************************************************** ****************/void T0_inter(void) interrupt 1{TH0 = 0xFC; //1msTL0 = 0x18;if(CS==0){EX1=1;//Usart_Send(0xbb);}if(CS==1){EX1=0;//Usart_Send(SPI_Data);}}/************************************************************** **********程序描述:外部中断0服务程序*************************************************************** ****************/void ExINT1_Interrupt(void) interrupt 2 using 0{SPI_Data = SPI_Data<<1;if(MOSI==1){SPI_Data |= 0x01;//Usart_Send(0x01);}else{SPI_Data&= ~0x01;//Usart_Send(0x00); }spi_flag++;if(spi_flag==8){spi_flag=0;Usart_Send(SPI_Data); SPI_Data=0;}}。
STM32之IO⼝模拟SPI本⽂介绍如何使⽤STM32标准外设库的GPIO端⼝模拟SPI,本例程使⽤PA5、PA6和PA7模拟⼀路SPI。
SPI有4种⼯作模式,模拟SPI使⽤模式0,即空闲时SCK为低电平,在奇数边沿采样。
本⽂适合对单⽚机及C语⾔有⼀定基础的开发⼈员阅读,MCU使⽤STM32F103VE系列。
1. 简介SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串⾏外围设备接⼝,是⼀种⾼速全双⼯的通信总线。
它被⼴泛地使⽤在要求通讯速率较⾼的场合。
SPI⽤于多设备之间通讯,分为主机Master和从机Slave,主机只有⼀个,从机可以有多个,通过⽚选信号对从机进⾏选择,⼀次只能选择⼀个从机。
通讯只能由主机发起,⽀持的操作分为读取和写⼊,即主机读取从机的数据,以及向从机写⼊数据。
SPI⼀般有4根线,分别是⽚选线SS、时钟线SCK、主设备输出\从设备输⼊MOSI、主设备输⼊\从设备输出MISO,其中除MISO对于主机为输⼊引脚外,其他引脚对于主机均为输出引脚。
因为有独⽴的输⼊和输出引脚,因此SPI⽀持全双⼯⼯作模式,即可以同时接收和发送。
2. 总线传输信号空闲状态:⽚选信号SS低电平有效,那么空闲状态⽚选信号SS为⾼。
开始信号及结束信号:开始信号需要将⽚选信号SS拉低,结束信号需要将⽚选信号SS拉⾼。
通讯模式:SPI有4种通讯模式,分别为0、1、2、3,根据时钟极性和时钟相位确定,时钟极性分别为空闲低电平和空闲⾼电平,时钟相位分别为SCK奇数边沿采样和偶数边沿采样。
常⽤的模式为模式0和模式3。
SPI模式时钟极性(空闲时SCK时钟)时钟相位(采样时刻)0低电平奇数边沿1低电平偶数边沿2⾼电平奇数边沿3⾼电平偶数边沿3. 时序说明以模式0举例说明:空闲状态:⽚选信号SS为⾼,SCK输出低电平。
开始信号:⽚选信号SS变低,SCK输出低电平。
结束信号:⽚选信号SS变⾼,SCK输出低电平。
单片机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();}}。