前言
这次来复习一下SPI以及ADC的有关知识,之前介绍到的磁编码器也是基于SPI协议通信才能读取其内部角度信息,ADC就更不用说了,在电压检测,电机驱动的方面都会涉及到采样量化编码的知识,趁此机会好好复习一下
参考资料
SPI通信协议详解(spi总线) - 知乎 (zhihu.com)
STM32F10xxx参考手册(中文).pdf
普中51单片机开发攻略--A2.pdf
SPI
介绍
这是一种全双工的串行外围总线,最少需要三根线,相较I2C而言,其优点是高速、能够同步通信
缺点是没有应答机制,接收数据时有一定缺陷
工作机制
如图所示,我们将SPI设备中的内部缓冲区称为SSPBUF,物理层面上是FIFO的形式用于保存接收或发送的数据
我们再通过移位寄存器SSPSR根据设置好的数据位宽把数据移入或者移出
通过配置与主控制电路相关的控制寄存器来选择SPI的工作模式
我们先不去看那些复杂的寄存器,我们先来看看SPI的引出的这四根线分别有什么作用
信号线
SCK:时钟信号,由主机向从机发送,在其上升沿或下降沿来决定数据的传输和速率
NSS/CS:片选信号,当总线上挂载了多个设备的时候,我们可以给每一个从机分配一个片选地址(Chip Select)以便主机能够与对应的从机进行通信
SDO/MOSI:数据的输出口,用于发送数据
SDI/MISI:数据的输入口,用于接收数据
配置寄存器
在上图中我们可以留意到有两个位,分别是CPOL和CPHA
CPOL配置时钟的极性,为1时代表空闲时为高电平,为0时代表空闲时为低电平
CPHA配置时钟的相位
我们知道一个时钟周期有两个跳变沿,因此CPHA决定的是从第几个脉冲开始采样,CPHA=0表示从第一个跳变沿采样,为1则从第二个跳变沿采样
举个例子,当CPHA = 0时,当CPOL = 1时,下降沿开始数据交换,当CPOL = 0时,上升沿开始数据交换
排列组合一下,我们可以得到四种模式
工作特点
同步通讯
由于SPI配备了时钟线,因此SPI设备可以通过时钟线进行实时通讯
数据交换
SPI协议规定一个SPI设备不能仅仅接收或者发送数据,对于一个设备而言,这两个工作应该是同时进行的,在每一个时钟周期内SPI设备都会发送并接收一个bit
而且在数据传输的过程中每次接收到的数据必须要在下一次数据传输之前采样,否则这些数据有可能会被丢弃
SPI只有主从模式,并没有读和写的概念
和前面的通讯形式稍有不同,全双工的SPI对时序的要求并不高
ADC
工作流程
其大致工作流程为:
ADC采样模拟信号 -> 采样信号保持 -> 低通滤波将模拟信号转换为数字信号 -> 根据ADC的分辨率量化信号的值 -> 对量化后的值进行编码
图中所示的A为滤波器电压传输系数,在采样周期下保持不变,保持周期下系数迅速下降,在这个周期里ADC将模拟信号转换为数字信号
分辨率的概念我在之前FOC篇中有提到,简单来说就是分辨率越大量化误差越小,测量到的精度越高
实现原理
逐次逼近型ADC
这种ADC的基本原理简单来说就是:
逐次逼近寄存器先写入高电压,经过DA转换后把数据和采样回来的信号进行比较,若采样信号大于逐次逼近寄存器电压则该位保留,否则置0,不断重复此过程直至逼近寄存器最低位,当转换结束后将逐次逼近寄存器的值存入缓冲寄存器,一个AD转换过程就完成了
双积分式ADC
基本原理如下:
第一步将输入电压变换成与其平均值成正比的时间间隔
接下来先将开关接通采样信号,将采样信号输入积分器,正向积分固定好的时间后再将开关接通参考电压,反向积分直至电压为0,系统在反向积分所经过的时间就是采样的电压值
简单来说就是先累加采样信号,然后用参考电压去抵消,抵消要用到的电压值就是采样信号的电压
XPT2046
这是一款 4 线制电阻式触摸屏控制器,内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器
XPT2046 支持从 1.5V 到 5.25V 的低电压 I/O 接口
XPT2046 能通过执行两次 A/D 转换查出被按的屏幕位置,除此之外, 还可以测量加在触摸屏上的压力
内部自带 2.5V 参考电压,可以作为辅助输入、 温度测量和电池监测之用,电池监测的电压范围可以从 0V 到 6V
XPT2046 片内集成有一个温度传感器
引脚介绍
X、Y、Z、VBAT、Temp 和 AUX 模拟信号经过片内的控制寄存器选择后进入 ADC
芯片部分并不是本文想要讲解的重点,这里就略过了
代码部分
#ifndef __XPT2046_H__
#define __XPT2046_H__
#define XPT2046_VBAT 0xAC //光敏电阻电压
#define XPT2046_AUX 0xEC
#define XPT2046_XP 0x9C //滑变电阻电压
#define XPT2046_YP 0xDC //热敏电阻电压
#define DELTA 0.02
unsigned int XPT2046_ReadAD(unsigned char Command);
#endif
#include <REGX52.H>
#include <INTRINS.H>
#include "XPT2046.h"
//引脚定义
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;
/**
* @brief ZPT2046读取AD值
* @param Command 命令字,范围:头文件内定义的宏,结尾的数字表示转换的位数
* @retval AD转换后的数字量,范围:8位为0~255,12位为0~4095
*/
unsigned int XPT2046_ReadAD(unsigned char Command)
{
unsigned char i;
unsigned int Data=0;
XPY2046_DCLK=0; //时钟线复位
XPY2046_CS=0; //片选线为低电平有效,查询从机地址
for(i=0;i<8;i++)
{
XPY2046_DIN=Command&(0x80>>i); //将指令输入,高位在前
XPY2046_DCLK=1; //上升沿进行数据转换
XPY2046_DCLK=0;
}
for(i=0;i<16;i++)
{
XPY2046_DCLK=1; //接收数据
XPY2046_DCLK=0;
if(XPY2046_DOUT){Data|=(0x8000>>i);} //接收从机发来的2字节数据
}
XPY2046_CS=1; //片选信号关闭,释放从机
return (Data>>8)*DELTA; //返回计算数值
}