×
单片机 > 单片机程序设计 > 详情

51单片机——SPI

发布时间:2020-06-15 发布时间:
|

UART、 I2C 和 SPI 是单片机系统中最常用的三种通信协议。

1、初步介绍

SPI 是一种高速的、全双工、同步通信总线,标准的 SPI 也仅仅使用 4 个引脚,常用于单片机和 EEPROM、FLASH、实时时钟、数字信号处理器等器件的通信。 SPI 通信原理比 I2C要简单,它主要是主从方式通信,这种模式通常只有一个主机和一个或者多个从机,标准的 SPI 是 4 根线,分别是 SSEL( 片选,也写作 SCS)、 SCLK( 时钟,也写作 SCK)、 MOSI( 主机输出从机输入Master Output/Slave Input) 和 MISO( 主机输入从机输出 Master Input/Slave Output)。


SSEL:从设备片选使能信号。如果从设备是低电平使能的话,当拉低这个引脚后,从设备就会被选中,主机和这个被选中的从机进行通信。
SCLK:时钟信号,由主机产生,和 I2C通信的 SCL 有点类似。
MOSI:主机给从机发送指令或者数据的通道。

MISO:主机读取从机的状态或者数据的通道。

 

2、工作模式

SPI 通信的主机也是我们的单片机,在读写数据时序的过程中,有四种模式;

CPOL:Clock Polarity,就是时钟的极性。通信的整个过程分为空闲时刻和通信时刻, 如果 SCLK 在数据发送之前和之后的空闲状态是高电平, 那么就是CPOL=1,如果空闲状态SCLK 是低电平,那么就是 CPOL=0。
CPHA: Clock Phase,就是时钟的相位。


  1. #include  

  2.   

  3. typedef unsigned char uchar;  

  4.   

  5. sbit DS1302_CE = P1 ^ 7;  

  6. sbit DS1302_CK = P3 ^ 5;  

  7. sbit DS1302_IO = P3 ^ 4;  

  8.   

  9. struct sTime   //日期时间结构体定义  

  10. {  

  11.   unsigned int year;  //年  

  12.   unsigned char mon;   //月  

  13.   unsigned char day;   //日  

  14.   unsigned char hour;  //时  

  15.   unsigned char min;   //分  

  16.   unsigned char sec;   //秒  

  17.   unsigned char week;  //星期  

  18. };  

  19.   

  20. /* 发送一个字节到DS1302通信总线上*/  

  21. void DS1302ByteWrite(uchar dat)  

  22. {  

  23.   uchar mask;  

  24.   

  25.   for (mask = 0x01; mask != 0; mask <<= 1) //低位在前,逐位移出  

  26.   {  

  27.     if ((mask & dat) != 0) //首先输出该位数据  

  28.     {  

  29.       DS1302_IO = 1;  

  30.     }  

  31.     else  

  32.     {  

  33.       DS1302_IO = 0;  

  34.     }  

  35.     DS1302_CK = 1;       //然后拉高时钟  

  36.     DS1302_CK = 0;       //再拉低时钟,完成一个位的操作  

  37.   }  

  38.   DS1302_IO = 1;           //最后确保释放IO引脚  

  39. }  

  40. /* 由DS1302通信总线上读取一个字节*/  

  41. uchar DS1302ByteRead()  

  42. {  

  43.   uchar mask;  

  44.   uchar dat = 0;  

  45.   

  46.   for (mask = 0x01; mask != 0; mask <<= 1) //低位在前,逐位读取  

  47.   {  

  48.     if (DS1302_IO != 0)  //首先读取此时的IO引脚,并设置dat中的对应位  

  49.     {  

  50.       dat |= mask;  

  51.     }  

  52.     DS1302_CK = 1;       //然后拉高时钟  

  53.     DS1302_CK = 0;       //再拉低时钟,完成一个位的操作  

  54.   }  

  55.   return dat;              //最后返回读到的字节数据  

  56. }  

  57. /* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节*/  

  58. void DS1302SingleWrite(uchar reg, uchar dat)  

  59. {  

  60.   DS1302_CE = 1;                   //使能片选信号  

  61.   DS1302ByteWrite((reg <

  62.   DS1302ByteWrite(dat);            //写入字节数据  

  63.   DS1302_CE = 0;                   //除能片选信号  

  64. }  

  65. /* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节*/  

  66. uchar DS1302SingleRead(uchar reg)  

  67. {  

  68.   uchar dat;  

  69.   

  70.   DS1302_CE = 1;                   //使能片选信号  

  71.   DS1302ByteWrite((reg <

  72.   dat = DS1302ByteRead();          //读取字节数据  

  73.   DS1302_CE = 0;                   //除能片选信号  

  74.   

  75.   return dat;  

  76. }  

  77. /* 用突发模式连续写入8个寄存器数据,dat-待写入数据指针*/  

  78. void DS1302BurstWrite(uchar *dat)  

  79. {  

  80.   uchar i;  

  81.   

  82.   DS1302_CE = 1;  

  83.   DS1302ByteWrite(0xBE);  //发送突发写寄存器指令  

  84.   for (i = 0; i 

  85.   {  

  86.     DS1302ByteWrite(dat[i]);  

  87.   }  

  88.   DS1302_CE = 0;  

  89. }  

  90. /* 用突发模式连续读取8个寄存器的数据,dat-读取数据的接收指针*/  

  91. void DS1302BurstRead(uchar *dat)  

  92. {  

  93.   uchar i;  

  94.   

  95.   DS1302_CE = 1;  

  96.   DS1302ByteWrite(0xBF);  //发送突发读寄存器指令  

  97.   for (i = 0; i 

  98.   {  

  99.     dat[i] = DS1302ByteRead();  

  100.   }  

  101.   DS1302_CE = 0;  

  102. }  

  103. /* 获取实时时间,即读取DS1302当前时间并转换为时间结构体格式*/  

  104. void GetRealTime(struct sTime *time)  

  105. {  

  106.   uchar buf[8];  

  107.   

  108.   DS1302BurstRead(buf);  

  109.   time->year = buf[6] + 0x2000;  

  110.   time->mon  = buf[4];  

  111.   time->day  = buf[3];  

  112.   time->hour = buf[2];  

  113.   time->min  = buf[1];  

  114.   time->sec  = buf[0];  

  115.   time->week = buf[5];  

  116. }  

  117. /* 设定实时时间,时间结构体格式的设定时间转换为数组并写入DS1302*/  

  118. void SetRealTime(struct sTime *time)  

  119. {  

  120.   uchar buf[8];  

  121.   

  122.   buf[7] = 0;  

  123.   buf[6] = time->year;  

  124.   buf[5] = time->week;  

  125.   buf[4] = time->mon;  

  126.   buf[3] = time->day;  

  127.   buf[2] = time->hour;  

  128.   buf[1] = time->min;  

  129.   buf[0] = time->sec;  

  130.   DS1302BurstWrite(buf);  

  131. }  

  132. /* DS1302初始化,如发生掉电则重新设置初始时间*/  

  133. void InitDS1302()  

  134. {  

  135.   uchar dat;  

  136.   struct sTime code InitTime[] =    //2016年5月18日9:00:00 星期二  

  137.   {  

  138.     0x2016, 0x05, 0x18, 0x09, 0x00, 0x00, 0x02  

  139.   };  

  140.   

  141.   DS1302_CE = 0;  //初始化DS1302通信引脚  

  142.   DS1302_CK = 0;  

  143.   dat = DS1302SingleRead(0);  //读取秒寄存器  

  144.   if ((dat & 0x80) != 0)      //由秒寄存器最高位CH的值判断DS1302是否已停止  

  145.   {  

  146.     DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据  

  147.     SetRealTime(&InitTime);      //设置DS1302为默认的初始时间  

  148.   }  

  149. }  



关键字:51单片机  SPI

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机中断源的扩展方法