驱动之SPI,UART,I2C的介绍与应用20170118
这篇文章主要介绍基本的驱动也是用的最多的协议类驱动中的SPI,I2C和UART。首先从最简单的UART也就是串口讲起:
1.UART
UART由两根线也就是TX,RX以及波特率产生器组成,操作比较简单,配置好后,就可以发送接收数据了,注意有的MCU需要接收数据时清除某些标记。如:
2.SPI
SPI一般有三根线组成即CLK,MOSI,MISO,数据输入和输出是单独的一根线。一般的操作都是先发控制指令,再发地址,接着才是数据。例:
3.I2C
I2C一般由两根线组成,即SDA,SCL,一根时钟线,一根数据线。关于I2C相关的开始信号,响应信号,停止信号时序见后面附录图片,这些信号一般都是通用封装好的,封装函数见附件(IO口模拟I2C)。
下面重点介绍I2C的使用操作,一般通信步骤是开始信号,从机地址+读或写标记,等待回应,发送数据,等待回应(接收数据,发送回应(最后一次接收则不发回应)),停止信号,代码示例:
最后,再总结与强调一下
SPI、I2C、UART三种串行总线协议的区别:
1,字面意思上:
SPI(Serial Peripheral Interface:串行外设接口);
I2C(INTER IC BUS)
UART(Universal Asynchronous Receiver Transmitter:通用异步收发器)
2.各总线的信号线:
SPI总线由三条信号线组成:串行时钟(SCLK)、串行数据输出(SDO)、串行数据输入(SDI)。SPI总线可以实现 多个SPI设备互相连接。提供SPI串行时钟的SPI设备为SPI主机或主设备(Master),其他设备为SPI从机或从设备(Slave)。主从设备间可以实现全双工通信,当有多个从设备时,还可以增加一条从设备选择线。
I2C总线是双向、两线(SCL、SDA)、串行、多主控(multi-master)接口标准,具有总线仲裁机制,非常适合在器件之间进行近距离、非经常性的数据通信。在它的协议体系中,传输数据时都会带上目的设备的设备地址,因此可以实现设备组网。一根数据线上传输的一条报文包括:开始信号+设备地址+命令+数据+(ACK)+停止信号
UART总线是异步串口,因此一般比前两种同步串口的结构要复杂很多,一般由波特率产生器(产生的波特率等于传输波特率的16倍)、UART接收器、UART发送器组成,硬件上由两根线,一根用于发送,一根用于接收。
从第二点明显可以看出,SPI和UART可以实现全双工,但I2C不行;
总结:I2C线更少,但是技术上也更加麻烦些,因为I2C需要有双向IO的支持,而且使用上拉电阻,抗干扰能力较弱,一般用于同一板卡上芯片之间的通信,较少用于远距离通信。SPI实现要简单一些,UART需要固定的波特率,就是说两位数据的间隔要相等,而SPI则无所谓,因为它是有时钟的协议。
个人学习笔记附录:
代码附件:
/*****************************************************************************
* Copyright (C) 2014-2015 China Aerospace Telecommunications Ltd. All rights reserved.
------------------------------------------------------------------------------
* File Module : PT810 dev_I2C.c
* Description : I2C Drive operation center
* Created : 2016.10.13.
* Author : Yu Weifeng
* Function List :
* Last Modified :
* History :
******************************************************************************/
#include "stm32f4xx_hal.h"
#include "CBasicTools.h"
#include "Config.h"
#include "dev_LightDistanceSensor.h"
#include "core_CM4.h"
#include "ucos_ii.h" static void I2C_DevConfig(void);
static void I2C_Start();
static void I2C_SendByte(u8 i_ucData);
static u8 I2C_ReadByte(u8 i_ucAck);
static u8 I2C_WaitAck();
static void I2C_Stop(); static T_I2C_DevManage g_tI2C_Dev ={
.name="I2C_Dev",
.DevConfig =I2C_DevConfig,
.DevI2C_Start =I2C_Start,
.DevI2C_SendByte =I2C_SendByte,
.DevI2C_ReadByte =I2C_ReadByte,
.DevI2C_WaitAck =I2C_WaitAck,
.DevI2C_Stop =I2C_Stop,
};
//IO方向设置
#define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式
#define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式 /*****************************************************************************
-Fuction : I2C_DevInit
-Description : I2C_DevInit
-Input :
-Output :
-Return : True/False
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
void I2C_DevInit()
{
RegisterI2C_Dev(&g_tI2C_Dev);
} /*****************************************************************************
-Fuction : DelayUs
-Description : DelayUs
-Input :
-Output :
-Return : True/False
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void DelayUs(u8 i_ucTime)
{
u16 wTime = *i_ucTime;
while(wTime--);
}
//延时nus
//nus:要延时的us数.
//nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*; //系统时钟晶振为84M晶振
OSSchedLock(); //阻止OS调度,防止打断us延时
told=SysTick->VAL; //刚进入时的计数器值
while()
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
OSSchedUnlock(); //恢复OS调度
} /*****************************************************************************
-Fuction : I2C_SDA_SET
-Description : I2C_SDA_SET
-Input :
-Output :
-Return : True/False
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static u8 I2C_SDA_SET(u8 i_ucSetValue)
{
u8 ret=FALSE;
if(GPIO_PIN_SET==i_ucSetValue)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET); //对应引脚PB
ret=TRUE;
}
else if(GPIO_PIN_RESET==i_ucSetValue)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET); //对应引脚PB
ret=TRUE;
}
else
{
ret=FALSE;
DebugPrintf(ERR"I2C_SDA_SET format err\r\n");
}
return ret;
}
/*****************************************************************************
-Fuction : I2C_SDA_READ
-Description : I2C_SDA_READ
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static u8 I2C_SDA_READ()
{
u8 ret=;
ret=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_9);
return ret;
}
/*****************************************************************************
-Fuction : I2C_SCL_SET
-Description : I2C_SCL_SET
-Input :
-Output :
-Return : True/False
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static u8 I2C_SCL_SET(u8 i_ucSetValue)
{
u8 ret=FALSE;
if(GPIO_PIN_SET==i_ucSetValue)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET); //对应引脚PB
ret=TRUE;
}
else if(GPIO_PIN_RESET==i_ucSetValue)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET); //对应引脚PB
ret=TRUE;
}
else
{
ret=FALSE;
DebugPrintf(ERR"I2C_SCL_SET format err\r\n");
}
return ret;
} /*****************************************************************************
-Fuction : I2C_DevConfig
-Description : I2C_DevConfig
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void I2C_DevConfig(void)
{
GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOH时钟 //PB8,9初始化设置
GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST; //快速
HAL_GPIO_Init(GPIOB,&GPIO_Initure); I2C_SDA_SET();
I2C_SCL_SET();
}
/*****************************************************************************
-Fuction : I2C_Start
-Description : I2C_Start//产生IIC起始信号
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/09/23 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void I2C_Start()
{
SDA_OUT(); //sda线输出
I2C_SDA_SET();
I2C_SCL_SET();
DelayUs();
I2C_SDA_SET();//START:when CLK is high,DATA change form high to low
DelayUs();
I2C_SCL_SET();//钳住I2C总线,准备发送或接收数据
}
/*****************************************************************************
-Fuction : I2C_Stop
-Description : I2C_Stop//产生IIC起始信号
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/09/23 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void I2C_Stop()
{
SDA_OUT();//sda线输出
I2C_SCL_SET();
I2C_SDA_SET();//STOP:when CLK is high DATA change form low to high
DelayUs();
I2C_SCL_SET();
I2C_SDA_SET();//发送I2C总线结束信号
DelayUs();
}
/*****************************************************************************
-Fuction : I2C_AckGenerate
-Description : I2C_AckGenerate////产生ACK应答
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void I2C_AckGenerate()
{
I2C_SCL_SET();
SDA_OUT();
I2C_SDA_SET();
DelayUs();
I2C_SCL_SET();
DelayUs();
I2C_SCL_SET();
}
/*****************************************************************************
-Fuction : I2C_AckGenerate
-Description : I2C_AckGenerate//////不产生ACK应答
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void I2C_AckNoGenerate()
{
I2C_SCL_SET();
SDA_OUT();
I2C_SDA_SET();
DelayUs();
I2C_SCL_SET();
DelayUs();
I2C_SCL_SET();
}
/*****************************************************************************
-Fuction : I2C_SendByte
-Description : I2C_SendByte////
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static void I2C_SendByte(u8 i_ucData)
{
u8 c;
SDA_OUT();
I2C_SCL_SET();//拉低时钟开始数据传输
for(c=;c<;c++)
{
I2C_SDA_SET((i_ucData&0x80)>>);
i_ucData<<=;
DelayUs(); //对TEA5767这三个延时都是必须的
I2C_SCL_SET();
DelayUs();
I2C_SCL_SET();
DelayUs();
}
}
/*****************************************************************************
-Fuction : I2C_OnDev
-Description : I2C_OnDev
//等待应答信号到来
//返回值:0,接收应答失败
// 1,接收应答成功 -Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/09/23 V1.0.0 Yu Weifeng Created
******************************************************************************/
static u8 I2C_WaitAck()
{
u8 ucErrTime=;
u8 ret=FALSE;
SDA_IN(); //SDA设置为输入
I2C_SDA_SET();
DelayUs();
I2C_SCL_SET();
DelayUs();
while(I2C_SDA_READ())
{
ucErrTime++;
if(ucErrTime>)
{
I2C_Stop();
ret=FALSE;
return ret;
}
}
I2C_SCL_SET();//时钟输出0
ret=TRUE;
return ret;
} /*****************************************************************************
-Fuction : I2C_ReadByte
-Description : I2C_ReadByte////
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
-Input :
-Output :
-Return :
* Modify Date Version Author Modification
* -----------------------------------------------
* 2016/10/13 V1.0.0 Yu Weifeng Created
******************************************************************************/
static u8 I2C_ReadByte(u8 i_ucAck)
{
u8 c;
u8 ucReceive=;
SDA_IN();//SDA设置为输入
for(c=;c<;c++ )
{
I2C_SCL_SET();
DelayUs();
I2C_SCL_SET();
ucReceive<<=;
if(I2C_SDA_READ())
ucReceive++;
DelayUs();
}
if (!i_ucAck)
I2C_AckNoGenerate();//发送nACK
else
I2C_AckGenerate(); //发送ACK
return ucReceive;
}
驱动之SPI,UART,I2C的介绍与应用20170118的更多相关文章
- SPI,UART,I2C都有什么区别,及其各自的特点
区别: SPI:高速同步串行口.3-4线接口,收发独立.可同步进行 UART:通用异步串行口.按照标准波特率完成双向通讯,速度慢 I2C:一种串行传输方式,三线制,网上可找到其通信协议和用法的 3根线 ...
- 常用协议(SPI, UART, I2C)
SPI: SPI是全双工的同步串行接口,数据速率可达几Mbps,在一般应用中有4根信号线:MOSI, MISO, SCK, SS. 根据时钟极性(CPOL)及相位(CPHA)不同可以组合成4种工作模式 ...
- SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)
SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...
- SPI、I2C、UART(转)
UART与USART(转) UART需要固定的波特率,就是说两位数据的间隔要相等. UART总线是异步串口,一般由波特率产生器(产生的波特率等于传输波特率的16倍).UART接收器.UART发送器组成 ...
- I2S/PCM/IOM-2、I2C/SPI/UART/GPIO/slimbus
概述 I2S,PCM,IOM-2都是数字音频接口,传数据的. I2C,SPI,UART,GPIO是控制接口,传控制信令的. I2S I2S(Inter-IC Sound Bus)是飞利浦公司为数字音频 ...
- Uart、SPI和I2C的区别
串口通信:UART.SPI.I2C区别[引用] 1.UART就是两线,一根发送一根接收,可以全双工通信,线数也比较少.数据是异步传输的,对双方的时序要求比较严格,通信速度也不是很快.在多机通信上面 ...
- UART、SPI和I2C详解
做单片机开发时UART,SPI和I2C都是我们最经常使用到的硬件接口,我收集了相关的具体材料对这三种接口进行了详细的解释. UART UART是一种通用串行数据总线,用于异步通信.该总线双向通信,可以 ...
- SPI、I2C、UART、I2S、GPIO、SDIO、CAN 简介
转自http://sanwen.net/a/fmxnjoo.html SPI.I2C.UART.I2S.GPIO.SDIO.CAN,看这篇就够了 总线 总线,总要陷进里面.这世界上的信号都一样,但是总 ...
- SPI、I2C、UART、I2S、GPIO、SDIO、CAN
总线,总线,总要陷进里面.这世界上的信号都一样,但是总线却成千上万,让人头疼. 总的来说,总线有三种:内部总线.系统总线和外部总线.内部总线是微机内部各外围芯片与处理器之间的总线,用于芯片一级的互连: ...
随机推荐
- 你的第一个接口测试:Python 接口测试
前言: 首先我们先明确一个概念,什么叫接口.什么叫接口测试? 接口的全称叫[Application Programming Interface 又叫API],是提供应用程序与开发人员基于某软件或硬件得 ...
- [Ubuntu] <uptime>命令
uptime 命令 就是查看系统启动时间的,前几个大家应该都很熟悉:当前时间.系统启动时间.正在登陆的用户数 最后的三个数字,分别代表过去 1分钟 5分钟 15分钟 的平均负载(Load Ave ...
- TW实习日记:第七天
今天早上,将项目的两个企业微信接口:登录和应用消息发送接口,做了最后的收尾工作,把目前我能解决的问题算是基本都解决了.早上还开了一个会,大意是组长封装了许多组件叫我们使用,在不断的使用中打磨组件的可用 ...
- XSS留言板实现
XSS 留言板实现-笔记 预备知识 XSS漏洞 XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS ...
- Python os.makedirs() 方法
os.makedirs() 方法用于递归创建目录.像 mkdir(), 但创建的所有intermediate-level文件夹需要包含子目录. 语法 makedirs()方法语法格式如下: os.ma ...
- 算法笔记(c++)--关于01背包的滚动数组
算法笔记(c++)--关于01背包的滚动数组 关于01背包问题:基本方法我这篇写过了. https://www.cnblogs.com/DJC-BLOG/p/9416799.html 但是这里数组是N ...
- 初创型公司如何经济有效的申请邓白氏编码(DUNS)
听说有免费,和800元,1500元,上万元等不同的申请方式?听说申请完还要等十数个工作日让邓白氏和苹果的数据库同步.不同高低价格的申请方式得到的编码都能被苹果接受吗? http://www.zhihu ...
- LeetCode 206. Reverse Linked List(C++)
题目: Reverse a singly linked list. Example: Input: 1->2->3->4->5->NULL Output: 5->4 ...
- 冲刺ing-3
第三次Scrum冲刺 队员完成的任务 队员 完成任务 吴伟华 分配任务,燃尽图 蔺皓雯 编写博客,美化主界面 蔡晨旸 美化主界面 曾茜 主页面设计 鲁婧楠 服务器建构 杨池宇 服务器建构 成员遇到的问 ...
- Python数据挖掘学习路程--起步
一.首先第一步我去了解了Python开发环境:Python(程序运行基础的解释器)+第三方类库(功能扩展)+编辑器(提高代码编辑效率) 编辑器有:Pycharm.Spyder.jupyter note ...