51单片机入门 - SPI总线

发布者:bemaii最新更新时间:2022-04-27 来源: eefocus关键字:51单片机  入门  SPI总线 手机看文章 扫描二维码
随时随地手机看文章

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,就是时钟的相位。


#include

 

typedef unsigned char uchar;

 

sbit DS1302_CE = P1 ^ 7;

 

sbit DS1302_CK = P3 ^ 5;

 

sbit DS1302_IO = P3 ^ 4;


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

 

{

 

  unsigned int year;  //年

 

  unsigned char mon;   //月

 

  unsigned char day;   //日

 

  unsigned char hour;  //时

 

  unsigned char min;   //分

 

  unsigned char sec;   //秒

 

  unsigned char week;  //星期

 

};

 

 

 

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

 

void DS1302ByteWrite(uchar dat)

 

{

 

  uchar mask;

 

 

 

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

 

  {

 

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

 

    {

 

      DS1302_IO = 1;

 

    }

 

    else

 

    {

 

      DS1302_IO = 0;

 

    }

 

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

 

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

 

  }

 

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

 

}

 

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

 

uchar DS1302ByteRead()

 

{

 

  uchar mask;

 

  uchar dat = 0;

 

 

 

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

 

  {

 

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

 

    {

 

      dat |= mask;

 

    }

 

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

 

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

 

  }

 

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

 

}

 

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

 

void DS1302SingleWrite(uchar reg, uchar dat)

 

{

 

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

 

  DS1302ByteWrite((reg << 1) | 0x80); //发送写寄存器指令

 

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

 

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

 

}

 

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

 

uchar DS1302SingleRead(uchar reg)

 

{

 

  uchar dat;

 

 

 

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

 

  DS1302ByteWrite((reg << 1) | 0x81); //发送读寄存器指令

 

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

 

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

 

 

 

  return dat;

 

}

 

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

 

void DS1302BurstWrite(uchar *dat)

 

{

 

  uchar i;

 

 

 

  DS1302_CE = 1;

 

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

 

  for (i = 0; i < 8; i++) //连续写入8字节数据

 

  {

 

    DS1302ByteWrite(dat[i]);

 

  }

 

  DS1302_CE = 0;

 

}

 

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

 

void DS1302BurstRead(uchar *dat)

 

{

 

  uchar i;

 

 

 

  DS1302_CE = 1;

 

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

 

  for (i = 0; i < 8; i++) //连续读取8个字节

 

  {

 

    dat[i] = DS1302ByteRead();

 

  }

 

  DS1302_CE = 0;

 

}

 

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

 

void GetRealTime(struct sTime *time)

 

{

 

  uchar buf[8];

 

 

 

  DS1302BurstRead(buf);

 

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

 

  time->mon  = buf[4];

 

  time->day  = buf[3];

 

  time->hour = buf[2];

 

  time->min  = buf[1];

 

  time->sec  = buf[0];

 

  time->week = buf[5];

 

}

 

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

 

void SetRealTime(struct sTime *time)

 

{

 

  uchar buf[8];

 

 

 

  buf[7] = 0;

 

  buf[6] = time->year;

 

  buf[5] = time->week;

 

  buf[4] = time->mon;

 

  buf[3] = time->day;

 

  buf[2] = time->hour;

 

  buf[1] = time->min;

 

  buf[0] = time->sec;

 

  DS1302BurstWrite(buf);

 

}

 

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

 

void InitDS1302()

 

{

 

  uchar dat;

 

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

 

  {

 

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

 

  };

 

 

 

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

 

  DS1302_CK = 0;

 

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

 

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

 

  {

 

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

 

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

 

  }

 

}


关键字:51单片机  入门  SPI总线 引用地址:51单片机入门 - SPI总线

上一篇:51单片机入门 - DS18B20温度传感器
下一篇:51单片机入门 - UART串口

推荐阅读最新更新时间:2024-11-09 22:29

8051单片机的UART0串口初始化
1、C8051f的UART0是异步、全双工串口。其波特率发生器规定由定时器1定时器提供。可配置为8位UART或9位UART(多机通讯第九位用于片选作用)。SYSCLK=24.5MHZ(我的板子采用内部晶振频率作为系统时钟) BAUDRATE=115200(波特率) 2、初值TH1 Tl1配置 由上述公式可计算初值:TH1 = 256-(SYSCLK/BAUDRATE/2)而程序内是TH1 = -(SYSCLK/BAUDRATE/2),这两种是相同的。第一种是以正数的二进制形式保存在计算机内。第二种是负数,取反加1求得补码保存在计算机中。结果是相同的。每当TL1中的值溢出后 TH1存储的重装载值装载到TL1中开始计数。
[单片机]
80<font color='red'>51单片机</font>的UART0串口初始化
单片机成长之路(51基础篇) - 010 51单片机的中断系统
一. 有关中断的概念 1. 仔细研什么叫中断?   举例:同学正在教室写作业,忽然被人叫出去,回来后,继续写作业这就是生活中的“中断”的现象,就是正常的工作过程被外部的事件打断了。 二. 引入计算机中断的概念。   中断的作用:     处理断电保存,解决快速CPU与慢速外设之间的矛盾等。对MCS-51单片机的中断系统用一句话讲叫:“五源中断,两级管理”中断请求源(五源中断)   五个中断源: 外部中断0(/INT0)   0003H T0溢出中断   000BH 外部中断1(/INT1)   0013H T1溢出中断   001BH 串口中断 入口地址     0023H   有了中断请
[单片机]
单片机成长之路(51基础篇) - 010 <font color='red'>51单片机</font>的中断系统
基于51单片机12864简易计算器
终于写计算器了,其实计算器老早就写好了的,只是那会一直在忙考试还有实验室项目,所以没能空出时间来写博客。现在寒假在家,终于可以静心的学点东西了。 下面就先写点自己写这个程序的过程。其实这是个单片机课的期末课题,但是没有几个能写的好的。计算器其实要考虑周全也是很复杂的,。但我们只要求做简易计算器,所以我的计算器只有整数加减乘除,带负数功能。经过检验,实用性还是可以的。 这个程序的整体思路很简单,主要是一些细节的处理。 思路是,先矩阵键盘扫描,监测运算符号按下,存储两个运算数,计算结果,整个过程的实时显示。 先是矩阵键盘扫描,我以前一直用的郭天祥教的方法,这种方法很好理解,但是缺点是代码太长了,于是我上网去找一种简单的矩阵键
[单片机]
51单片机启动代码:STARTUP.A51
通过Keil编译器建立工程时,Keil会提示是否添加STARTUP.A51文件到工程,该文件即为51单片机启动代码。 51单片机复位后马上执行STARTUP.A51文件中的启动代码,根据启动代码中的设置依次执行以下操作: 内部RAM清零 外部RAM清零 清零分页的外部RAM 初始化SMALL内存模型的可重入模拟堆栈及其堆栈指针 初始化LARGE内存模型的可重入模拟堆栈及其堆栈指针 初始化COMPACT内存模型的可重入模拟堆栈及其堆栈指针 初始化8051单片机的硬件堆栈指针 将系统控制权转交给初始化全局变量的代码,如果没有被初始化的全局变量则转交给C程序文件中的main函数。 STARTUP.A51启动文件中定
[单片机]
51单片机模拟SPI总线通信程序及proteus仿真
分享一个51单片机模拟SPI总线来进行通信的程序及仿真 仿真原理图如下 单片机源程序如下: #include reg51.h //包含单片机寄存器的头文件 #include intrins.h //包含_nop_()函数定义的头文件 //x5045引脚定义 sbit SCK=P3^4; //将SCK位定义为P3.4引脚 sbit SI=P3^5; //将SI位定义为P3.5引脚 sbit SO=P3^6; //将SO位定义为P3.6引脚 sbit CS=P3^7; //将SCK位定义为P3.7引脚 //功能变量定义 #define WREN 0x06 //写使能锁存器允许 #define WRD
[单片机]
<font color='red'>51单片机</font>模拟<font color='red'>SPI总线</font>通信程序及proteus仿真
MCS-51单片机的内部结构
1、8051单片机片内并行接口 2、MCS-51的内部资源 3、 MCS-51的芯片引脚 图1-8 MCS-51引脚图 4、单片机的工作方式 单片机的工作方式包括:复位方式、程序执行方式、单步执行方式、低功耗操作方式以及EPROM编程和校验方式。 1. 复位方式:经典的上电复位电路 2. 程序执行方式:(1)执行内部程序;(2)执行外部程序 3. 单步执行方式:用于调试程序和系统 4. 低功耗操作方式 5. 编程和校验
[单片机]
MCS-<font color='red'>51单片机</font>的内部结构
STM32小白入门(第12天)---I2C协议
一、概述 二、信号概念 三、AT24C02(EEPROM电可擦除ROM)--配合单片机存贮掉电前需要保存的数据,类似单片机的硬盘 1、写时序 2、读时序 思考题2:在24c02控制时钟的时候,为什么要进行5us的延时,小于5us延时或许大于5us的延时是否可以,示例代码如下: //设置SCL高电平 SCL=1; delay_us(5); //设置SCL低电平 SCL=0; delay_us(5); 回答:大于5us是可以的,如果使用5ms是可以的。但是延时是不能低于1.2us,详细描述如下图。 3、起始信号和停止信号 //sda输入输出模式切换函数 v
[单片机]
STM32小白<font color='red'>入门</font>(第12天)---I2C协议
AT89S51单片机扩展EEPROM AT2864的设计
  2864A与AT89S51单片机的接口电路如下图所示。 2864A的片选端CE与高地址线P2.7连接,P2.7=0才能选中2864A。这种线选法决定了2864A对应多组地址空间,即0000H~1FFFH,2000H~3FFFH,4000H~5FFFH,6000H~7FFFH。当系统中有其他ROM和RAM 存储器 时,要统一考虑编址问题。      这8K字节存储器可作为数据存储器使用,但掉电后数据不丢失。      AT89S51对2864A进行写操作时所用指令包括: AT89S51对2864A进行读操作时所用指令包括: 下面介绍对2864A装载一个页面数据(16个字节)的子程序W
[单片机]
AT89S<font color='red'>51单片机</font>扩展EEPROM AT2864的设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved