常用串行通信

串行通信的速度较并行低,但是非常节省端口资源,所以是底层经常接触到的通信方式。

一、串口通信

二、I2C通信

以MPU6050惯性传感器为例,编写模拟I2C的主机程序

2.1编写分段函数

2.1.1发起开始命令(Start condition)

  I2C总线平常处于空闲状态,SDA和SCL均为高电平。发起开始命令的做法是,SDA从高到低跳变,I2C总线从空闲->忙  

  void IIC_WriteStartCondition(void)

  {

    IIC1_SDA_HIGH;

    IIC1_SCK_HIGH; //如图开始的时候两个数据都处于高电平

    IIC_Delay(2); //延时一段时间后

    IIC1_SDA_LOW; //SDA先与SCL拉低,即为起始条件

    IIC_Delay(2);     //延时一段时间后

    IIC1_SCK_LOW; //SCL拉低,并开始第一针数据(ADDRESS)的收发,也是起始条件结束

    IIC_Delay(1); //延时半个周期为下一个函数作准备

  }

2.1.2数据传输函数

  数据传输中,SDA电平改变只能发生在SCL为低的期间,根据时序图,可以知道在发送起始条件后需要发送从机地址和写位,表示对总线上相应的从机进行写操作:

  void I2C_WriteByteDataToSlave(uint8_t data)

  {

    IIC1_SCK_LOW; //再次拉低数据线,可以忽略

    for(i=0;i<8;i++) //发送一个字节(8位数据)

    {

      (data & 0x80) ? IIC1_SDA_HIGH : IIC1_SDA_LOW;//判断数据最高位是否为1,若是拉高数据线,否则拉低数据线,表示传输字节1/0

      data <<= 1; 把数据左移1位,把刚刚发送完的数据剔除

      IIC1_SCK_HIGH;//拉高时钟线表示1个位传输结束

      IIC_Delay(1);   //延时半个周期

      IIC1_SCK_LOW; //把SCL拉到低电平准备发送下一位数据

      IIC_Delay(1);

    }

  }

2.1.3 等待应答

  I2C发送第一帧数据完毕后,需要等待从机返回应答以确保它收到了信息。等待应答的时候主机释放SDA线,从机接管SDA并保证其低电平直到下一个SCL高电平结束,编程上这里使第9个SCL信号拉高后,一直读取SDA信号直到出现低电平才跳出,最后主机拉低SCL,拉高SDA

  Uint8_t IIC_WaitSlaveAsck(void)

  {

    uint8_t tim = 0;

    IIC1_SCK_HIGH;   //拉高SCL线

    while(IIC1_SDA_DATA) //当数据线为高电平

    {

      tim++;

      Delay(1);

      if(tim > 50) //设计一个倒计时,超过50ms则认为从机无应答,I2c出错,返回1

         {

           tim=0;

          I2CERR++;

        return 1;

        }

    }

    IIC_Delay(1);

    IIC1_SCK_LOW;

    IIC1_SDA_HIGH;

    IIC_Delay(1);

    return 0; //返回0

  }

2.1.4发起停止(Stop condition)

  停止信号后释放I2C总线,总线返回空闲状态,操作是当SCL在高电平时,SDA发生从第到高的跳变

  

  void IIC_StopCondition(void)

  {

    IIC1_SDA_LOW;//先让SDA处于低电平

    IIC1_SCK_HIGH;//拉高SCL线

    IIC_Delay(2);//延时

    IIC1_SDA_HIGH;//SDA发生从低到高的跳变

    IIC_Delay(2);//延时一段时间等待通信结束

  }

2.1.5数据接收

  当我们进行MPU6050的读取操作时,需要接收来自MPU6050的数据,具体操作为如2.1.1发起Start  然后发送地址及读取位,之后产生SCL时钟信号,并释放SDA线由MPU6050接管,在SCL高电平接收数据  

  uint8_t IIC_ReadByteDataFromSlave(void)

  {

    uint8_t i,data=0;

    for(i=0;i<8;i++)

    {

      IIC1_SCK_HIGH; //拉高时钟线

      IIC_Delay(1); //延时一个周期

      data <<= 1; //把数据左移一位

      data |= IIC1_SDA_DATA; //把新来的数据加在位

      IIC1_SCK_LOW; //拉低时钟线

      IIC_Delay(1); //延时

    }

    return data; //返回接收到的数据

  }

2.1.6主机应答

  在接收到MPU6050的数据时,需要作出应答(连读模式时)来告诉MPU6050继续发送下一帧数据,或者不作出应答直接发出Stop condition表示通信结束

  void IIC_MastAsckToSlave(void)

  {

    IIC1_SCK_LOW;

    IIC1_SDA_LOW;

    // IIC_Delay(1);

    IIC1_SCK_HIGH;

    IIC_Delay(1);

    IIC1_SCK_LOW;

    IIC1_SDA_HIGH;

    IIC_Delay(1);

  }

  void IIC_MastNoteAsckToSlave(void)

  {

    IIC1_SCK_LOW;

    IIC1_SDA_HIGH;

    // IIC_Delay(1);

    IIC1_SCK_HIGH;

    IIC_Delay(1);

    IIC1_SCK_LOW;

    IIC_Delay(1);

  }

2.2编写整段读取

2.2.1 单字节写:

本段函数中分为8个部分,分别是:产生起始信号、写入从机地址+写位、等待应答、写入寄存器地址、等待应答、写入数据、等待应答、产生停止信号。根据已写成的函数进行组合

void MPU6050_SingleByteWrite_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress, uint8_t Data )

{

  IIC_WriteStartCondition();      //1

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);//2

  IIC_WaitSlaveAsck();    //3

  IIC_WriteByteDataToSlave(RegisterAddress);        //4

  IIC_WaitSlaveAsck();    //5

  IIC_WriteByteDataToSlave(Data);    //6

  IIC_WaitSlaveAsck();    //7

  IIC_StopCondition();    //8

}

2.2.2爆发写(连续写)

关键在于发送寄存器地址以后可以一直只发送数据进行写入,所以利用循环体。

void MPU6050_BurstWrite_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress, uint8_t* DataPointer, uint8_t DataLength )

{

  u8 i;

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);

  IIC_WaitSlaveAsck();

  IIC_WriteByteDataToSlave(RegisterAddress);

  IIC_WaitSlaveAsck();

  for(i=0;i<DataLength;i++)

  {

    IIC_WriteByteDataToSlave(*(DataPointer+i));

    IIC_WaitSlaveAsck();

  }

  IIC_StopCondition();

}

2.2.3单字节写

本函数分为11段:分别是 起始条件、从机地址加写、等待应答、寄存器地址、等待从机应答、再次发送起始条件、从机地址加读、等待应答、读取数据、不应答,停止条件

uint8_t MPU6050_SingleByteRead_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress )

{

  uint8_t Data;

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);

  IIC_WaitSlaveAsck();

  IIC_WriteByteDataToSlave(RegisterAddress);

  IIC_WaitSlaveAsck();

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS+1);

  IIC_WaitSlaveAsck();

  Data = IIC_ReadByteDataFromSlave();

  MastNoteAsckToSlave();

  IIC_StopCondition();

  return Data;

}

2.2.4爆发式读(连读)

同理爆发写

void MPU6050_BurstRead_Soft( I2C_TypeDef* I2Cx, uint8_t RegisterAddress, uint8_t* DataPointer, uint8_t DataLength )

{

  uint8_t i;

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS);

  IIC_WaitSlaveAsck();

  IIC_WriteByteDataToSlave(RegisterAddress);

  IIC_WaitSlaveAsck();

  IIC_WriteStartCondition();

  IIC_WriteByteDataToSlave(MPU6050_I2C_ADDRESS+1);

  IIC_WaitSlaveAsck();

  for(i=0;i<DataLength-1;i++)

  {

     * (DataPointer+i)=IIC_ReadByteDataFromSlave();

    MastAsckToSlave();

}

  * (DataPointer+i)=IIC_ReadByteDataFromSlave();

  MastNoteAsckToSlave();

  IIC_StopCondition();

}

三、SPI通信

时间: 2024-11-04 01:49:48

常用串行通信的相关文章

【技术总结】几种常用的无线串行通信技术

与传统的有线串行(RS232)通信不同,无线串行通信具有设备移动方便(特别在通信设备空间相互隔离不便连线的情况下).通信距离远(可达几十公里)等特点. 无线串行通信应用领域非常广,常用的有:PLC无线通讯:无线抄表:工业遥控遥测:无线数据传输:银行POS系统:无线数据采集:楼宇自动化.无线监控.门禁系统:智能家居.工业控制:汽车检测设备:无线LED显示屏系统等. 目前,比较常用的无线串行通信技术有红外.蓝牙.ZigBee和RF无线数传等四种.四种方式都有标准模块,特别适用于嵌入式系统及PC机之间

使用win32 API 实现串行通信 (一)

本文基于wince平台,使用win32 API实现串行通信 1.打开和关闭串行端口 串行端口设备使用CreateFile函数打开,所使用的名称要遵循特定的格式,即3个字符 COM后紧跟要打开的COM端口号,再加个冒号,冒号是Windows CE所必需的. 如,hser=CreateFile(TEXT(“COM1:”),GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,0,NULL),为以可读可写的方式打开COM1端口. 调用CloseHandle函

linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件.#include <asm/***.h> 是在linux-2.6.29/arch/arm/include/asm下面寻找源文件.#include <mach/***.h> 是在linux-2.6.29/arch/ar

串行通信概念解析

串行通信是指 使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度.其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机.计算机与外设之间的远距离通信. 串行通信可以分为同步串行通信和异步串行通信 同步通信(时钟同步) 同步通信是一种连续串行传送数据的通信方式,一次通信只传送一帧信息.这里的信息帧与异步通信中的字符帧不同,通常含有若干个数据字符. 它们均由同步字符.数据字符和校验字符(CRC)组成.其中同步字符位于帧开头,用于确认数据字符的开始.数据字符在同步

Linux驱动开发常用头文件

头文件目录中总共有32个.h头文件.其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个.这些头文件各自的功能如下: 1.主目录 <a.out.h>:a.out头文件,定义了a.out执行文件格式和一些宏.<const.h>:常数符号头文件,目前仅定义了i节点中i_mode字段的各标志位.<ctype.h>:字符类型头文件,定义了一些有关字符类型判断和转换的宏.<errno.h>:错误号头文件,包含系统中各种出错号.(

Matlab与单片机的串行通信及数据处理

http://hi.baidu.com/20066203/blog/item/891edf52f73278040df3e360.html 摘要:结合单片机和Matlab两者优点,基于事件驱动中断通信机制,提出一种Matlab环境下PC机与单片机实时串行通信及数据处理方法:完成单片机数据采集系统与PC机RS-232/RS-485串行通信及其通信数据分析处理.文件存储.FIR滤波及图形显示:简化系统开发流程,提高开发效率.该方法已成功应用于一个PIC16F876单片机应用系统实例之中. 关键词:PI

转载:Linux 下C编程常用的头文件

头文件主目录include 头文件目录中总共有32个.h头文件.其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个.这些头文件各自的功能如下,具体的作用和所包含的信息请参见第14章. <a.out.h>:a.out头文件,定义了a.out执行文件格式和一些宏. <const.h>:常数符号头文件,目前仅定义了i节点中i_mode字段的各标志位. <ctype.h>:字符类型头文件,定义了一些有关字符类型判断和转换的宏. <

&lt;2014 04 29&gt; *nix环境编程常用库总结

-------------------------linux常用头文件如下:POSIX标准定义的头文件<dirent.h>        目录项<fcntl.h>         文件控制<fnmatch.h>    文件名匹配类型<glob.h>    路径名模式匹配类型<grp.h>        组文件<netdb.h>    网络数据库操作<pwd.h>        口令文件<regex.h>   

【ALB技术笔记】基于多线程方式的串行通信接口数据接收案例

基于多线程方式的串行通信接口数据接收案例 广东职业技术技术学院  欧浩源 1.案例背景 在本博客的<[CC2530入门教程-06]CC2530的ADC工作原理与应用>中实现了电压数据采集的程序设计,传感器模块以每1秒发送一帧数据的形式通过串口向上位机发送电压数据.其数据帧由4个字节组成:一个帧头和一个帧尾,中间两个字节为电压数据,其格式如下: 帧头(0xAF)    电压数据高8位    电压数据低8位    帧尾(0xFA) 在篇博文中,将讲述如何通过多线程的方式,从串口接收传感器发送过来的