STC15W4K58S4单片机SPI通讯实验1

                                      STC15W4K58S4单片机SPI通讯实验1

SPI通讯实验1:

一个主机,一个从机,三线连接,不需要片选线。PC机通过串行口向主单片机发送一个字节的数据,主单片机接收到后向从机发送这个字节,从机接收后将数据返回给主机,主机再将数据通过串行口发送回PC机。

串行口波特率9600bps 无奇偶校验 8个数据位 1个停止位

单片机系统时钟频率SYS_clk=22.1184MHz

SPI通信速率SYS_clk/4

电路连接图:

两个单片机可以使用不同的供电电源,但是要共地,串行口的地线也要与两个单片机共起来。

两块单片机的SPI引脚连接时,中间一定要串联上240欧的电阻,以防止程序失误出现端口短路烧毁的情况!

采用寄存器引脚切换,SPI_S1  SPI_S0

                                                    0            1

 /SS:P2.4  MOSI:P2.3  MISO:P2.2  SCLK:P2.1

主机从机都使用这组引脚作为SPI通信端口。主机采用查询方式,从机采用SPI中断方式。

使用SPI通讯需要设置  SPCTL寄存器

位号

D7

D6

D5

D4

D3

D2

D1

D0

位名称

SSIG

SPEN

DORD

MSTR

CPOL

CPHA

SPR1

SPR0

1

1

1

1

0

0

0

0

对于主机,永远无需使用片选线所以SSIG位置1(不使用片选SS)

启动SPI硬件通讯,SPEN=1(启动)

字符传输顺序DORD=1,低位在前高位在后

设备设置为主机MSTR=1(主机)

CPOL=0,时钟极性设置为空闲时低电平

CPHA=0,时钟相位设置为前沿采样,后沿输出

SPR1 SPR0 设置为00,SPI传输速度为SYSclk/4(系统时钟的4分频)

因此 SPCTL=11110000B=0xF0;

如果是从机的话,MSTR为设置为0

因此 SPCTL=11100000B=0xE0;

由于电路连接关系的限制,需要做SPI管脚切换

AUXR1辅助功能寄存器1:

位号

D7

D6

D5

D4

D3

D2

D1

D0

位名称

S1_S1

S1_S0

CCP_S1

CCP_S0

SPI_S1

SPI_S0

0

DPS

其中SPI_S1和SPI_S0是SPI引脚切换选择位:

SPI_S1

SPI_S0

SPI接口引脚位置

SS/

MOSI

MISO

SCLK

0

0

P1.2

P1.3

P1.4

P1.5

0

1

P2.4

P2.3

P2.2

P2.1

1

0

P5.4

P4.0

P4.1

P4.3

1

1

无效

设置SPI_S1和SPI_S0为01,即切换管脚为:

SS:P2.4,MOSI:P2.3,MISO:P2.2,SCLK:P2.1

设置辅助功能寄存器AUXR1时为了不改变其它位的值,首先使用与操作清零SPI_S1 SPI_S0

AUXR1&=0xF3;    //1111 0011  将位3,位2清0

之后使用或操作将SPI_S1,SPI_S0置为01

 AUXR1|=0x04;    //0000 0100   将位3,位2置1

这样就只改变了SPI_S1,SPI_S0的值,而其它位不变。

主机从机都做如此设置。

主要函数说明:SPI主机部分

//串行口1初始化

//系统时钟频率SYSclk=22.1184MHz,波特率9600,8个数据位无奇偶校验

//使用定时器T2作为波特率发生器

void UART1_init(void)

{

 //设置SCON寄存器,使用串口1,定时器T2

 //SM0 SM1 SM2 REN TB8 RB8       TI RI

 // 0       1        0      1       0      0         0  0

 //SM0 SM1=01:工作于8位波特率可变,使用定时器T1或T2

 //REN=1:允许接收

 SCON=0x50;   //这个寄存器主要是设置串口工作模式,波特率可变,8位,允许接收的

 //设置辅助功能寄存器AUXR

 //T0x12 T1x12 UART_M0x6 T2R T2_C/T T2x12 EXTRAM S1ST2

 //                                                                     1                        1

 AUXR|=0x01;   //S1ST2=1:串口1使用定时器T2作为波特率发生器

 AUXR|=0x04;   //T2x12=1:T2不分频

 //设置T2初值,波特率9600bps

 T2L=0xC0 ;  //设定定时器T2初值

 T2H=0xFD; 

 AUXR|=0x10;  //T2R=1:开启定时器T2

 ES=0;      //关闭串口1中断,主机采用串口查询方式,所以这里关闭中断

 EA=1;   //开启总中断

}

//设置SPI控制寄存器SPCTL

//使SPI工作与主机模式,无需片选

//时钟极性CPOL=0,时钟相位CPHA=0

//通讯速度位系统时钟频率的1/4

//并开启硬件SPI通讯

SPCTL=0xF0;      //SPI控制寄存器      从机设置为0xE0 

//做SPI管脚切换

//使用SS:P2.4   MOSI:P2.3   MISO:P2.2   SCLK:P2.1

void Switch_port() 

{

 AUXR1&=0xF3;    //1111 0011  将位3,位2清0

 AUXR1|=0x04;    //0000 0100  将位3,位2置1

}

//主函数

int main(void)

{

 uchar xdata i;

 uchar xdata SPI_status;  //用于读取SPI传输状态(是否完成)

 port_mode();         //设置所有端口为准双向弱上拉的模式,就是保持与传统51单片机一至

//系统上电提示灯闪烁3次,表示程序开始执行

  for(i=1; i<=3; i++)

  {

   LEDG=0; Delay500ms();  

   LEDG=1;Delay500ms();

  }

  LCD1602_Init();  //LCD1602初始化

  UART1_init();    //串行口1初始化,9600bps,8个数据位,波特率可变,由T2产生

  SPCTL=0xF0;     //SPI控制寄存器   从机设置为0xE0 

  Switch_port();   //SPI引脚切换  使用 P2.4  P2.3  P2.2  P2.1

  //在LCD1602上显示

  WriteString(0,0,"===SPI Master==1");

//程序没有使用中断方式,使用查询方式

//进入主循环

while(1)

{

 if(RI)  //如果有串行口接收标志

 {

  revDat=SBUF;   //读取由串口发送来的数据

  RI=0;                       //清串口接收标志

  LEDG=0;                //点亮提示灯

  //显示串口接到的数据

//%bx表示以16进制输出,占2个字符,不足补0

//显示格式:U S:0X**  R:0X**

//其中U表示串口  S表示发送的数据  R表示接收的数据  0X表示十六进制数

  sprintf(disptemp,"U S:0X%02bX  R:0X%02bX",sendDat,revDat);     

WriteString(0,0,disptemp);

  //将串口收到的数据从SPI端口发送给从机

  SPDAT=revDat;   

  //在屏幕的第二行显示SPI端口收发数据的情况

  //S S:0X**  R:0X**

  //S表示SPI端口  S表示发送的数据  R 表示接收的数据  0X表示十六进制数

  sprintf(disptemp,"S S:0X%02bX  R:0X%02bX",revDat,SPI_buffer);

  WriteString(1,0,disptemp);

  //通过查询SPI状态寄存器SPSTAT,判断数据发送是否完成

  SPI_status=0;

  while(SPI_status==0)  //等待SPIF=1即等待SPI发送完毕

  {

   SPI_status=SPSTAT;  //读取SPSTAT状态寄存器的值

   SPI_status=SPI_status&0x80;  //获得第7位的值,这一位为1表明SPI传输完成

  }

  SPSTAT=0xC0;       //写1清除SPIF和WCOL,WCOL是写冲突标志,

//写冲突是指SPI移位寄存器中的数据还没有发送完成的时候,又有新的数据写入移位寄存器

//则这个错误标志WCOL被置1

//这里不必做检测

//接收从机传来的数据

SPI_buffer=SPDAT;  //保存SPI口收到的数据

 //在LCD1602的第二行显示SPI收发数据

  sprintf(disptemp,"S S:0X%02bX  R:0X%02bX",revDat,SPI_buffer);

  WriteString(0,1,disptemp);

  SBUF=SPI_buffer;   //将收到的数据从串口发送到计算机

  sprintf(disptemp,"U S:0X%02bX  R:0X%02bX",SPI_buffer,revDat); //%bx表示以16进制输出,占2个字符,不足补0

  WriteString(0,0,disptemp);

  while(TI==0);      //等待发送完成

  TI=0;             //清除串口发送中断标志

 }

}

 return 0; 

}

//从机程序

//从机使用SPI中断方式

//主要函数说明:

//SPI中断服务程序

void SPI_routine(void) interrupt 9

{

 SPSTAT=0xC0;     //写1清0  SPI接收中断标志和写冲突标志

 SPI_buffer=SPDAT;  //将SPI端口接到的数据保存到变量中

 SPI_Receive=1;     //设置接收完成软件标志

}

int main(void)

{

 uchar xdata i;

 port_mode();  //设置为准双向弱上拉的模式,就是保持与传统51单片机一至

  //系统提示灯闪烁3次,表明系统上电工作

   for(i=1; i<=3; i++)

  {

   LEDG=0; Delay500ms();

   LEDG=1; Delay500ms();

  }

  LCD1602_Init();  //LCD1602初始化

  UART1_init();    //串行口1初始化

  Switch_port();   //SPI管脚切换 使用P2.4 P2.3 P2.2 P2.1

 SPCTL=0xE0;   //SPI控制寄存器          从机设置为0xE0 

 IE2=IE2|0x02;  //ESPI=1,允许SPI产生中断

 EA=1;

 SPI_Receive=0; //清除SPI软件接收标志

  WriteString(0,0,"===SPI SLAVE===1");

//进入主循环

while(1)

{

 if(SPI_Receive)   //判断SPI是否接收到数据

 {

//%bx表示以16进制输出,占2个字符,不足补0

  sprintf(disptemp,"Rev0X%02bX",SPI_buffer);     

  WriteString(0,1,disptemp);

  SPI_Receive=0;      //清除软件SPI标志

  SPDAT=SPI_buffer;   //接收到的数据送SPDAT,准备下一次通讯时发回

 }  

}

 return 0; 

}

源码下载:百度网盘下载

提取码:293o

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值