驱动之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
总线,总线,总要陷进里面.这世界上的信号都一样,但是总线却成千上万,让人头疼. 总的来说,总线有三种:内部总线.系统总线和外部总线.内部总线是微机内部各外围芯片与处理器之间的总线,用于芯片一级的互连: ...
随机推荐
- 【洛谷】题解 P1056 【排座椅】
题目链接 因为题目说输入保证会交头接耳的同学前后相邻或者左右相邻,所以一对同学要分开有且只有一条唯一的通道才能把他们分开. 于是可以吧这条通道累加到一个数组里面.应为题目要求纵列的通道和横列的通道条数 ...
- 小白初识 - 计数排序(CountingSort)
计数排序,属于桶排序特殊的一种. 当要排序n个数据的时候,如果所处的范围不大,我们可以取其中的最大值K,并将数据分散在K个桶里面, 每个桶里面的数据都是相同的(这样省去了桶内排序的时间),然后顺序取出 ...
- PHP核心技术——魔术方法
魔术方法: 魔术方法是以两个下画线开头.具有特殊作用的一些方法,可以看做PHP的"语法糖". set和get方法: class Account{ private $user=1; ...
- JAVA学习笔记--初始化与清理
编写程序时,常会由于变量没有初始化而产生各种错误:用完一个元素,如果不将其占用的内存资源释放,则会导致资源耗尽,这也很严重,为此,C++引入了构造器的概念,这是一个在创建对象时被自动调用的特殊方法,以 ...
- Linux学习——操作文件与目录
1. ls:列出文件及目录信息. 命令格式:ls [选项] ... 常用选项: -a 显示指定目录下所有子目录与文件,包括隐藏文件. -A 显示指定目录下所有子目录与文件,包括隐藏文件.但不列出“.” ...
- 技嘉主板+AMD CPU开启CPU虚拟化方法
硬件环境:技嘉AB350+AMD Ryzen 5 1600X 由于安装虚拟机的需要,所以要开启CPU的虚拟化. 首先进入BIOS. 然后如图:(M.I.T-高级频率设定-CPU超频进阶设置-SVM M ...
- Windows下IntelliJ IDEA中调试Spark Standalone
参考:http://dataknocker.github.io/2014/11/12/idea%E4%B8%8Adebug-spark-standalone/ 转载请注明来自:http://www.c ...
- Struts2(二)
以下内容是基于导入struts2-2.3.32.jar包来讲的 1.关于StrutsPrepareAndExecuteFilter 启动StrutsPrepareAndExecuteFilter时加载 ...
- 0302IT行业虽吃香,能完全享受这块“香"的也很难
面对现今严峻的就业形势,越来越多的人希望通过职业技能培训或者学历提升来提高自己的综合技能以便能够顺利地应聘到自己理想中的工作. 在2014年十大最热门行业和职业排行榜中IT行业最吃香.在十大行业里,I ...
- 蜗牛慢慢爬 LeetCode 8. String to Integer (atoi) [Difficulty: Medium]
题目 Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cas ...