精华内容
下载资源
问答
  • 基于MC9S12XS128单片机的AD数据采集系统(HC-05蓝牙无线串口传输) 说明 对多个传感器进行供电,并采集传感器输出的模拟电压信号,无线传输至电脑接收终端,对数据进行保存分析。因为应用场景为采集光敏电阻及...

    基于MC9S12XS128单片机的AD数据采集系统(HC-05蓝牙无线串口传输)

    image-20210825154550844
    image-20210825154915027

    说明

    对多个传感器进行供电,并采集传感器输出的模拟电压信号,无线传输至电脑接收终端,对数据进行保存分析。因为应用场景为采集光敏电阻及湿度传感器等传统的传感器信号,所以这里依然选择自带ADC的MC9S12XS128作为本次设计的主控芯片。由于应用主要是简单的ADC数据采集及无线串口传输,这里选择引脚数最少的封装LQFP64。如下图所示。

    image-20210825161508975

    硬件选型

    MCU

    MCU选择MC9S12XS128MAE(LQFP64),MC9S12XS128 是 16 位单片机,由 16 位中央处理单元(CPU12X)、128KB 程序、Flash(P-lash)、8KB RAM、8KB 数据 Flash(D-lash)组成片内存储器。LQFP64封装的现在某宝上有很多,但不一定都有货,价格也差别很大,下单前最好问一下客服有没有货,而且最近大部分芯片都在涨价。

    无线传输

    无线串口传输选用HC-05,最高可以实现1382400bps传输速率,传输距离10米(这里是HC-05官方网站),因为我们这里所接收端是电脑上的,且现在大多数台式电脑都自带蓝牙,所以HC-05只需要一个,用于连接MC9S12XS128就可以,电脑端只需要用自带的蓝牙接收HC-05的数据即可。为了使设计出的板子整体美观,这里选用贴片的HC-05,如下图所示(HC-05使用手册),不同于常用的带底板的HC-05,贴片的HC-05核心板需要外围辅助电路才能正常工作。这里从HC-05使用手册上可以找到,对应的外围电路(手册上的有点糊,后面原理图上我有画,比较高清)。

    image-20210825163717678

    电源部分

    5V电源

    5v电源用于板载供电,来源包括 外部供电与锂电池供电,当处于外部供电时,通过usb口电源连接至LM2940-5.0输出5v电压用于板子整体供电(这里是加5v稳压芯片是为了保证板子电源以及后续锂电池充电不受usb口输出电压的影响,usb口5v电压输入情况下,LM2490实际输出会小于5v。这里usb口设计主要是用于对锂电池充电设计,所以只要最终大于4.65v即可,为啥是4.65v马上就会说明)。LM2940封装选用TO-263(LM2940手册)下面是我在手册上复制出来的封装引脚定义以及LM2940输入与输出电压说明。(特别注意的是检查 绘制的TO-263封装4引脚连接的为GND,不要设计成与3脚OUT或者1脚IN电气相同,否则会出现板子电源正负短接)

    image-20210825171016836
    1. Input Voltage Range = 6 V to 26 V
    2. Dropout Voltage Typically 0.5 V at Iout=1A

    为了实现无线数据采集及传输,当然需要一个内部电源对板子进行供电,而不是外接电源线进行实时供电,这样不就违背设计无线的初心了吗,那么现在需要一个内部电源进行供电,而现在锂电池的输出电压绝大部分都是3.7v的,而我们现在需要5v电压,所以肯定不能直接将锂电池接入板子上进行供电;同时,锂电池本身也需要充电,才能维持一段时间的持续供电。基于这些原因,我们需要选择一个锂电池充放电管理芯片,实现输出5v电压,以及可以为锂电池本身进行充电。这里我选用的是ESOP8封装的ip5306(ip5306),该芯片可以实现5v 2.4A输出,输入电压范围为4.65v~5.5v。满足我们当前设计要求。当然我这里选择ip5306的原因一方面是因为引脚数少,方便焊接,一方面是方便后续的检测。如果想DIY设计更高级的,也可以选择比较强的芯片代替,比如支持多种快充协议的sw6206。大家按需选择。下图是Ip5306典型应用原理图。

    ip5306典型简化应用原理图

    3.3V电源

    电路上的3.3v电源是对HC-05核心板进行供电使用,这里选用SOT-223封装的AMS1117-3.3,该芯片输入接上面所设计的5v电源,输出的3.3v电源对HC-05进行供电。(AMS1117-3.3中文手册)同样需要注意下图红色标识引脚为Vout,而不是GND。

    image-20210825175637132

    串口部分

    对比了CH340系列的串口芯片,选用最简的CH340N芯片,封装为sop-8,内置独立的收发缓冲区,支持通讯波特率100bps~2Mbps,这里2Mbps在串口通信里是相当大的了。

    image-20210825183514208

    需要注意的是,8引脚,大多数板子电源都为5v,所以,按照说明要求接0.1uf的退耦电容,不然在串口通信时会出现各种bug,尤其是通信波特率高的时候。1、2引脚,分别接接D+、D-。而6脚TXD接MCU的RXD,7脚RXD接TXD,这里需要特别注意,相同的连在一起将无法传输数据

    CH340N串口引脚MCU串口引脚
    6-TXD50(PS0)-RXD0
    7-RXD51(PS1)-TXD0

    硬件设计

    原理图

    总体原理图设计如上图所示。(原理图pdf源文件)

    渲染图是用keyshot9软件渲染的。(关于PCB如何渲染

    硬件选型 部分已经进行相关介绍,这里就不进行赘述了。在上面全部硬件焊接完成后,可以进行将锂电池接上,将供电开关S1拨至锂电池侧进行供电,正常情况下,锂电池电量LED指示灯点亮,以及电路电源指示灯点亮。连接上micro-usb数据线,将s2开关拨至DC电源侧,电池开始充电,电量指示灯最高指示灯开始闪烁,说明充电电路正常运行。

    蓝牙HC-05配置

    下面我们先对HC-05进行配置

    HC-05进入AT模式

    拨码开关sw4 1、2打开,其它保持关闭状态,先让HC-05的AT引脚置高进入AT模式,即按住按键sw1,接上micro-usb数据线,另一端接上电脑的usb口上进行上电,松开sw1,当D1灯变为慢闪,则表明HC-05已经进入AT模式;

    查找COM号

    我的电脑->右键->管理 打开界面如下,选择 设备管理器,下拉 端口,可以看到所连接板子的端口号为COM19(带CH340字样的端口)。

    image-20210825204315460

    开始AT模式调试

    打开电脑的串口调试助手,设置波特率为38400bps(这里的波特率是HC-05进入AT模式后固定的)。

    配置蓝牙 (发送以下AT指令后返回OK表示设置成功)

    1. 恢复默认设置:AT+ORGL\r\n(\r\n即回车、换行,在串口调试助手上输入一个回车即可)
    2. 配置蓝牙的名称:AT+NAME=Bluetooth_M\r\n
    3. 配置蓝牙的配对码:AT+PSWD=1234\r\n(配对码设置为四位,需要记住,后面电脑连接配对时需要用到)
    4. 将蓝牙A配置为主机模式:AT+ROLE=1\r\n(板子实时采集数据并主动向外发送,所以设置为主机模式)
    5. 配置波特率、停止位和校验位:AT+UART=115200,0,0\r\n,设置蓝牙通信串口波特率为115200,停止位1位,无校验位(这里设置的波特率是当HC-05正常工作时的通信速率,而不是更改AT模式下固定的38400bps波特率)

    电脑连接HC-05进行配对

    上一步中,配置的蓝牙名称为Bluetooth_M、配对码为1234,一会我们会用到。

    先对板子重新上电,使得HC-05进入正常模式

    打开电脑蓝牙设置,电脑自带蓝牙的话,在桌面右下角可以看到蓝牙的图标,左键单击,选择 添加蓝牙设备,则可以打开如下界面,左键单击 添加蓝牙或其他设备,

    image-20210825212519205

    弹出如下列表,选择第一项,等待一会,就可以看到Bluetooth_M设备名称,左键单击,将会进行配对,将会弹出输入配对码的窗口,此时输入上一步设置的1234配对码,确认后便可配对上。如果未搜索到Bluetooth_M设备,请确认是否重新上电重启板子。

    image-20210825212614841

    至此,完成蓝牙的设置及配对工作,接下来,进行MCU程序编写。

    亚克力外壳设计

    为了提高板子本身的应用环境的绝缘抗噪性能,我这里将PCB导出的.stp文件导入进Rhino7(犀牛7),简单画了一下外壳,由四块亚克力板组成,外壳形状相信大家都看到了,下面内嵌的2600mAh锂电池尺寸为(7.1mm * 46mm * 70mm)。四块亚克力外壳加工.ai文件,在文章的最后,也会一并分享给大家。

    image-20210825154915027

    程序设计

    文章最后会把该程序的工程文件打包分享给大家。

    程序设计主要思路是通过MC9S12XS128的ADC口进行8通道数据采集(LQFP64封装只有PAD00~PAD07八个ADC引脚)。这里需要特别注意使用printf时

    printf("%.3f,%.3f,%.3f,%.3f\n",channel1,channel2,channel3,channel4);

    需要在main.c文件上加入TERMIO_PutChar函数,不需要在主函数中调用。否则无法串口打印输出数据。至于为什么可以看这篇文章 Freescale CodeWarrior 中使用 printf( ) 函数

    void TERMIO_PutChar(char C) 
    {
      while(!(SCI0SR1&0x80));
      SCI0DRL=C;
    }
    

    本次程序设计的是通过8路ADC实现4路差分信号的采集,并实时通过串口输出,在这里即为HC-05串口输出。

    这里是串口调试助手接收的数据截图,可以看到可以正常接收数据。

    关于程序是如何编写的我也不过多的说明,在下面的源代码中都有相应的中文注释,帮助理解。

    在这里安利一下,如果大家目前想使用飞思卡尔MC9S12XS128这个芯片进行系统设计的话,一方面肯定是参考官方提供的手册最为权威(手册链接失效戳这),但我推荐入门看MC9S12单片机原理及嵌入式应用开发技术书上的讲解及示例都非常好,毕竟是中文的,书的链接在这,我在某东和某宝查了一下,现在出第二版的了,有条件的读者推荐购买纸质的,阅读体验肯定比电子版的好,我现在只找到第一版的分享给大家。

    主程序main.c

    #include <hidef.h>
    #include "derivative.h"
    #include <stdio.h>
    #include "init.h"
    void TERMIO_PutChar(char C) 
    {
      while(!(SCI0SR1&0x80));
      SCI0DRL=C;
    }
    void main(void)
    {
      float channel1,channel2,channel3,channel4;
      DisableInterrupts;        //关闭中断
    	INIT_AD();               //AD初始化,八通道,8位
    	INIT_PLL();
    	INIT_SCI0();
    	EnableInterrupts;         //打开中断
    	for(;;)
    	{
    	while(!(ATD0STAT0&0X80));             //查询ATD是否完成
    	channel1=(float)(channel_1L-channel_2L)*5/255;
    	channel2=(float)(channel_3L-channel_4L)*5/255;
    	channel3=(float)(channel_5L-channel_6L)*5/255;
    	channel4=(float)(channel_7L-channel_8L)*5/255;
    	printf("%.3f,%.3f,%.3f,%.3f\n",channel1,channel2,channel3,channel4);
    	}
    }
    
    
    

    init.h

    #include <hidef.h>
    #define     channel_1H     ATD0DR0H
    #define     channel_1L     ATD0DR0L
    #define     channel_2H     ATD0DR1H
    #define     channel_2L     ATD0DR1L
    #define     channel_3H     ATD0DR2H
    #define     channel_3L     ATD0DR2L
    #define     channel_4H     ATD0DR3H
    #define     channel_4L     ATD0DR3L
    #define     channel_5H     ATD0DR4H
    #define     channel_5L     ATD0DR4L
    #define     channel_6H     ATD0DR5H
    #define     channel_6L     ATD0DR5L
    #define     channel_7H     ATD0DR6H
    #define     channel_7L     ATD0DR6L
    #define     channel_8H     ATD0DR7H
    #define     channel_8L     ATD0DR7L
    
    void INIT_PLL(void);
    void INIT_SCI0(void);
    void SCI0_send(unsigned char data); 
    unsigned char SCI0_receive(void);
    void INIT_SCI1(void);
    void SCI1_send(unsigned char data); 
    unsigned char SCI1_receive(void);
    void init_pwm(void); 
    void delay(void);
    void INIT_AD(void); 
    unsigned char AD_capture(unsigned char chanel); 
    void initialize_tim(void);
    void DFlash_Init(void);
    void DFlash_Write(word ADDR16,word a,word b,word c,word d);
    unsigned int DFlash_Read (word destination);
    void DFlash_Erase(word ADDR16);
    void SPI_Init(void);
    byte SPI_Byte(byte value);
    

    init.c

    #include "derivative.h"      /* derivative-specific definitions */
    #include "init.h"      
    
    #define  BUS_CLOCK		   80000000	   //总线频率,改变总线频率直接在此处修改
    #define  OSC_CLOCK		   16000000	   //晶振频率
    #define   BAUD           115200      //串口波特率
    
    #define READword(address)     ((unsigned int)(*(volatile unsigned int *__near)(address)))
    
    #define DFLASH_LOWEST_START_PAGE        0x00        //定义data flash的起始页
    #define DFLASH_START                    0x00100000  //定义data flash的起始地址
    #define DFLASH_PAGE_SIZE                0x0400      //定义data flash的大小为1K.
    #define DFLASH_PAGE_WINDOW_START        0x0800      //定义data flash页面窗口的起始地址
    
    unsigned int duoji=7500;
    unsigned int motor=1000;
    
    
    
    /*************************************************************/
    /*                      初始化锁相环                         */
    /*************************************************************/
    void INIT_PLL(void) 
    {
        CLKSEL &= 0x7f;       //设置OSCCLK作为系统时钟
        PLLCTL &= 0x8F;       //禁止锁相环
    
        //PLLCLK=2×OSCCLK×(SYNR+1)/(REFDV+1), fbus=PLLCLK/2
        #if(BUS_CLOCK == 120000000) 
            SYNR = 0xcd;
        #elif(BUS_CLOCK == 104000000) 
          SYNR = 0xcc;
        #elif(BUS_CLOCK == 96000000) 
          SYNR = 0xcb;
        #elif(BUS_CLOCK == 88000000) 
          SYNR = 0xca;
        #elif(BUS_CLOCK == 80000000) 
          SYNR = 0xc9;
        #elif(BUS_CLOCK == 72000000) 
          SYNR = 0xc8;
        #elif(BUS_CLOCK == 64000000) 
          SYNR = 0xc7;
        #elif(BUS_CLOCK == 56000000) 
          SYNR = 0xc6;
        #elif(BUS_CLOCK == 48000000) 
          SYNR = 0xc5;
        #elif(BUS_CLOCK == 40000000) 
          SYNR = 0x44;
        #elif(BUS_CLOCK == 32000000)
          SYNR = 0x43;     
        #elif(BUS_CLOCK == 24000000)
          SYNR = 0x42;
        #elif(BUS_CLOCK == 16000000)
          SYNR = 0x01;
    
       #endif 
    
        REFDV = 0x81;
        PLLCTL |=0x70;  //使能锁相环
        asm NOP;
        asm NOP;
        while(!(CRGFLG&0x08)); //PLLCLK锁定
        CLKSEL |= 0x80;        //设置PLLCLK为系统时钟
    
    }
    
    /*************************************************************/
    /*                        初始化SCI0                         */
    /*************************************************************/
    void INIT_SCI0(void) 
    {
      SCI0BD = BUS_CLOCK/16/BAUD;   //设置SCI0波特率为115200
      SCI0CR1 = 0x00;        //设置SCI0为正常模式,八位数据位,无奇偶校验
      SCI0CR2 = 0x0c;        //允许接收和发送数据
    }
    
    /*************************************************************/
    /*                       串口发送函数                        */
    /*************************************************************/
    void SCI0_send(unsigned char data) 
    {
      while(!SCI0SR1_TDRE);         //等待发送数据寄存器(缓冲器)为空
      SCI0DRL = data;
    }
    
    /*************************************************************/
    /*                       串口接收函数                        */
    /*************************************************************/
    unsigned char SCI0_receive(void) 
    {
      while(!SCI0SR1_RDRF);          //等待发送数据寄存器满
      return(SCI0DRL);
    }
    
    /*************************************************************/
    /*                        初始化SCI1                         */
    /*************************************************************/
    void INIT_SCI1(void) 
    {
      SCI1BD = BUS_CLOCK/16/BAUD;   //设置SCI1波特率为115200
      SCI1CR1 = 0x00;        //设置SCI1为正常模式,八位数据位,无奇偶校验
      SCI1CR2 = 0x0c;        //允许接收和发送数据
    }
    
    /*************************************************************/
    /*                       串口发送函数                        */
    /*************************************************************/
    void SCI1_send(unsigned char data) 
    {
      while(!SCI1SR1_TDRE);         //等待发送数据寄存器(缓冲器)为空
      SCI1DRL = data;
    }
    
    /*************************************************************/
    /*                       串口接收函数                        */
    /*************************************************************/
    unsigned char SCI1_receive(void) 
    {
      while(!SCI1SR1_RDRF);          //等待发送数据寄存器满
      return(SCI1DRL);
    }
    
    /*************************************************************/
    /*                        初始化PWM                          */
    /*************************************************************/
    void init_pwm(void) 
    {
      PWMCTL_CON01= 1;   //通道01为16位的PWM
      PWMCTL_CON23= 1;   //通道23为16位的PWM
      PWMCTL_CON45= 1;   //通道45为16位的PWM
    
      PWMPOL_PPOL1= 1;   //通道的极性为高电平有效
      PWMPOL_PPOL3= 0;   //通道的极性为低电平有效,这一点很重要。
      PWMPOL_PPOL5= 1;   //通道的极性为高电平有效
    
      PWMPRCLK = 0x33;   //A时钟和B时钟的分频系数为8,频率为10MHz
      PWMSCLA  =    1;   //SA时钟频率为5MHz
      PWMSCLB  =    1;   //SB时钟频率为5MHz
      PWMCLK   = 0x20;   //45用SA时钟作为时钟源,01和23用A,B时钟
      PWMCAE   = 0x00;   //脉冲模式为左对齐模式
    
      PWMPER01  =  2000;   //通道01的频率为5KHz,用于H桥的驱动 
      PWMPER23  =  2000;   //通道23的频率为5KHz,用于H桥的驱动 
      PWMPER45  = 50000;   //周期10ms,用于舵机的驱动
    
      PWMDTY01  =  motor;    //通道01的占空比设置  
      PWMDTY23  =  motor;    //通道23的占空比设置
      PWMDTY45  = duoji;     //通道45的占空比设置
    
      PWME_PWME1=0;          //禁能通道01,使用时再将该位置一
      PWME_PWME3=0;          //禁能通道23,使用时再将该位置一
      PWME_PWME5=0;          //禁能通道45,使用时再将该位置一
    }
    
    /*************************************************************/
    /*                        延时函数                           */
    /*************************************************************/
    void delay(void) 
    {
    unsigned int i;
    for(i=0;i<50;i++) 
     {
      asm("nop"); 
     }
    }
    
    /*************************************************************/
    /*                      初始化AD模块                         */
    /*************************************************************/
    void INIT_AD(void)
    {
     ATD0CTL1 = 0x00;
    
     ATD0CTL2 = 0x40;
     ATD0CTL3 = 0xc0;
     ATD0CTL4 = 0x02;
     ATD0CTL5 = 0x30;
    }
    
    /*************************************************************/
    /*                        起动AD转换                         */
    /*************************************************************/
    unsigned char AD_capture(unsigned char chanel) 
    {
     unsigned char AD_data;
     switch(chanel)
     { 
      case 0:
        ATD0CTL5 = 0x00;    //转换AD00
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 1:
        ATD0CTL5 = 0x01;    //转换AD01
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 2:
        ATD0CTL5 = 0x02;    //转换AD02
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 3:
        ATD0CTL5 = 0x03;    //转换AD03
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 4:
        ATD0CTL5 = 0x04;    //转换AD04
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 5:
        ATD0CTL5 = 0x05;    //转换AD05
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 6:
        ATD0CTL5 = 0x06;    //转换AD06
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 7:
        ATD0CTL5 = 0x07;    //转换AD07
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 8:
        ATD0CTL5 = 0x08;    //转换AD08
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 9:
        ATD0CTL5 = 0x09;    //转换AD09
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 10:
        ATD0CTL5 = 0x0a;    //转换AD10
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 11:
        ATD0CTL5 = 0x0b;    //转换AD11
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 12:
        ATD0CTL5 = 0x0c;    //转换AD12
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 13:
        ATD0CTL5 = 0x0d;    //转换AD13
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 14:
        ATD0CTL5 = 0x0e;    //转换AD14
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
      case 15:
        ATD0CTL5 = 0x0f;    //转换AD15
        while(!ATD0STAT0_SCF);
        AD_data = ATD0DR0L;
        break;
    
     }
     return(AD_data);
    }
    
    /************************************************************/
    /*                    初始化TIM模块                         */
    /************************************************************/
    void initialize_tim(void)
    {
      TSCR1_TFFCA = 1;  // 定时器标志位快速清除
      TSCR1_TEN = 1;    // 定时器使能位. 1=允许定时器正常工作; 0=使主定时器不起作用(包括计数器)
      TIOS  = 0xfe;      //指定通道0为输入捕捉方式,其余通道为输出比较方式
      TCTL4 = 0x01;	    // 设置通道0为捕捉上升沿方式
      TIE   = 0x01;     // 允许通道0定时中断
      TSCR2 = 0x07;	    // 预分频系数pr2-pr0:111,时钟周期为1.6us,
      TFLG1 = 0xff;	    // 清除各IC/OC中断标志位
      TFLG2 = 0xff;     // 清除自由定时器中断标志位
    }
    
    /*************************************************************/
    /*                      初始化DFLASH                         */
    /*            DFLASH的相对地址范围为0x0000-0x1fff            */
    /*************************************************************/
    void DFlash_Init(void)
    {
       while(FSTAT_CCIF==0);            //等待正在处理的FLASH操作完成
       FCLKDIV=0x0F;                    //外部晶振为16M.FLASH时钟不超过1M,具体参照手册
       FCNFG=0x00;                      //禁止中断
       while(FCLKDIV_FDIVLD==0);        //等待时钟设置成功
    }
    
    /*************************************************************/
    /*                     向DFLASH写入数据                      */
    /*                ADDR16为写入数据的首地址                   */
    /*                 a,b,c,d为写入的数据                    */
    /*************************************************************/
    void DFlash_Write(word ADDR16,word a,word b,word c,word d)
    {
        while(FSTAT_CCIF==0); 
        if(FSTAT_ACCERR)           //判断并清除标志位;
            FSTAT_ACCERR=1;
        if(FSTAT_FPVIOL)           //判断并清除标志位;
            FSTAT_FPVIOL=1;
        FCCOBIX_CCOBIX=0x00; 
        FCCOB=0x1110;         //写入命令和高位地址
        FCCOBIX_CCOBIX=0x01;  //地址后16位
        FCCOB=ADDR16;         //写入低16位地址
        FCCOBIX_CCOBIX=0x02;  //写入第一个数据
        FCCOB=a;
        FCCOBIX_CCOBIX=0x03;  //写入第二个数据
        FCCOB=b;
        FCCOBIX_CCOBIX=0x04;  //写入第三个数据
        FCCOB=c;
        FCCOBIX_CCOBIX=0x05;  //写入第四个数据
        FCCOB=d;  
          
    
        FSTAT_CCIF=1;         //写入执行命令
        while(FSTAT_CCIF==0); //等待执行完毕
    
    }
    
    /*************************************************************/
    /*                     由DFLASH读取数据                      */
    /*              destination为读取数据的地址                  */
    /*************************************************************/
    word DFlash_Read (word destination)
    {
        byte   lastepage;          //用于存储EPAGE的值
        byte   epage;              //用于计算EPAGE的值
        unsigned int data;         //读取出的数据
    
        lastepage = EPAGE;   //保存EPAGE的值
        
        epage = (byte)((DFLASH_LOWEST_START_PAGE)+(destination >>10));   //计算EPAGE
        EPAGE=epage;                                                     //给EPAGE赋值
         
        data = READword((destination & (DFLASH_PAGE_SIZE - 1)) + DFLASH_PAGE_WINDOW_START);  //读取页面窗口中的数据
        
        EPAGE= lastepage;       //恢复EPAGE的值
        
        return(data);
    
    }
    
    /*************************************************************/
    /*                    擦除DFLASH的一个分区                   */
    /*************************************************************/
    void DFlash_Erase(word ADDR16)
    {   
      while(FSTAT_CCIF==0);
      if(FSTAT_ACCERR)           //判断并清除标志位;
          FSTAT_ACCERR=1;
      if(FSTAT_FPVIOL)           //判断并清除标志位;
          FSTAT_FPVIOL=1;
    
      FCCOBIX_CCOBIX=0x00;
      FCCOB=0x1210;           //写入擦除命令和高位地址
      FCCOBIX_CCOBIX=0x01;   
      FCCOB=ADDR16;           //写入低16位的地址
      FSTAT_CCIF=1;           //启动执行命令
      while(FSTAT_CCIF==0);   //等待执行完成
    }
    
    /*************************************************************/
    /*                      初始化SPI模块                        */
    /*************************************************************/
    void SPI_Init(void) 
    {
      DDRS    = 0xE0;  //设置接口为输出   
      SPI0CR2 = 0x00;  //SS管脚为普通I/O
      SPI0CR1 = 0x5e;  //使能SPI,设置为主模式
      SPI0BR  = 0x83; //设置波特率为1M                  
    }
    
    /*************************************************************/
    /*                      SPI读写一个字节                      */
    /*************************************************************/
    byte SPI_Byte(byte value)
    {
    	while (!SPI0SR_SPTEF);
    	SPI0DRL = value;
    	while(!(SPI0SR_SPIF));
    	return SPI0DRL;
    }
    

    关于程序下载

    编译与下载程序需要软件codewarrior以及BDM下载器(飞翔)

    BDM驱动安装可以看我之前写的文章(戳这)里面有相关的介绍,也可以配合看MC9S12单片机原理及嵌入式应用开发技术第三章中安装教程。

    包括驱动文件下载,及codewarrior的下载链接,这里就不重复了。

    最后

    源文件分享,如果文章的 手册 等 跳转链接失效,大家可以私信或者评论区回复需要的文件及邮箱,我看到会通过邮件附件的形式分享。

    阿里云盘(阿里这里无法分享犀牛.3dm文件)

    百度云盘 提取码:1002

    谷歌云盘

    展开全文
  • openmv串口传输代码

    千次阅读 2020-12-23 03:33:16
    功能是找到指定颜色物体中心坐标,再串口发送。我用openmv加无线传输模块发送数据给单片机处理。import sensor, image, timefrom pyb import UARTimport jsonthreshold = [(37, 67, 45, 84, 4, 68), #red(34, 67, -...

    功能是找到指定颜色物体中心坐标,再串口发送。我用openmv加无线传输模块发送数据给单片机处理。

    import sensor, image, time

    from pyb import UART

    import json

    threshold = [(37, 67, 45, 84, 4, 68),         #red

    (34, 67, -55, -22, 2, 41),      #green

    (25, 67, -37, 26, -63, -26)]    #blue

    #设置红色的阈值,括号里面的数值分别是L A B 的最大值和最小值(minL, maxL, minA,

    # maxA, minB, maxB),LAB的值在图像左侧三个坐标图中选取。如果是灰度图,则只需

    #设置(min, max)两个数字即可。

    sensor.reset()

    sensor.set_pixformat(sensor.RGB565)

    sensor.set_framesize(sensor.QVGA)

    sensor.skip_frames(time = 2000 )

    sensor.set_auto_whitebal(False)

    #关闭白平衡。白平衡是默认开启的,在颜色识别中,需要关闭白平衡。

    clock = time.clock()

    uart = UART(3, 115200)

    uart.init(115200, bits=8, parity=None, stop=1)  #8位数据位,无校验位,1位停止位、

    while(True):

    clock.tick()

    img = sensor.snapshot()

    blob = img.find_blobs(threshold, area_threshold=300)

    if blob: #如果找到了目标颜色

    # print(blob)

    # uart.write("B3 B3 ")    #一帧数据的帧头

    FH = bytearray([0xb3,0xb3])

    uart.write(FH)

    for b in blob:

    #迭代找到的目标颜色区域

    img.draw_rectangle(b[0:4]) # rect

    img.draw_cross(b[5], b[6]) # cx, cy

    x = b.cx()

    y = b.cy()

    print(x, y, end = ',')

    data = bytearray([x,y])

    uart.write(data)

    print(clock.fps())

    展开全文
  • 通过串口传输数据三、总结参考文献 一、串口通信概述 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。 串行接口简称为串口,串行接口 (Serial Interface)是指数据一位一位...

    一、串口通信概述

    串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。

    串行接口简称为串口,串行接口 (Serial Interface)是指数据一位一位地顺序传送。实现双向通信就需要一对传输线,即TX与RX线。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

    1. 串口如何连接

    电路连接方式:
    串口如果要实现双向传输,则设备1与设备2,TX与RX要交叉相连。
    在这里插入图片描述
    起始位: 数据线TX由高电平变为低电平。
    停止位: 数据线TX由低电平变为高电平。

    起始位和停止位作用:
      如果接收设备检测到数据线由高电平变为低电平,就是接收到了来自发送设备的起始信号,表示开始数据的传输。如果接收设备检测到数据线由低电平变为高电平,就是接收到了来自发送设备的停止信号,表示一帧数据的结束,通过以上特点接收设备就可以将中间的8bit有效数据解析出来,这样就完成了一帧数据的传输。

    2. 如何计算波特率

    串口传输格式:我们通常用的串口传输格式为:1bit起始位+8bit数据位+1bit停止位(无奇偶校验位),如下图所示
    在这里插入图片描述
    所以传输1Byte数据串口需要传输10bit数据。上面计算得传输1Bit需要的时间为8.68us,则传输1Byte需要时间为8.68*10=86.8us。

    波特率
      由基础知识知50M系统时钟—波特率为115200条件下传输1bit需要计数个数为434。那么1Byte(串口传输格式为:1bit起始位+8bit数据位+1bit停止位)是不是循环计数10次434就可以传输完毕。

    要注意的是,串口通信的两台主机之间,波特率要一致,下面两图演示了波特率一致与不一致的情况

    收发波特率一致:
    在这里插入图片描述

    收发波特率不一致:
    在这里插入图片描述
    计算公式
    以波特率115200为例

    波特率115200 = 115200 (位/秒)。

    如果没有校验位,就应该除以 10,得到的是每秒字节数:波特率115200 = 115200 (位/秒) = 11520 (字节/秒)

    再除以 1024,就是每秒 KB 数:波特率115200 = 115200 (位/秒) = 11.25 (KB/秒)。如果有一位奇偶校验位,就应该除以 11,得到的是每秒字节数。

    最后得出:波特率115200 = 115200 (位/秒) = 10.27 (KB/秒)


    二、实验演示

    1. 实验设备

    • 两个USB TO TTL
    • 两台PC机
    • 杜邦线若干
    • 串口助手软件

    2. 实际电路连接

    连接方法与之前的理论一致,解法见下表,电源可以不接,可以通过电脑供电。

    USB TO TTL 1USB TO TTL 2
    TXRX
    RXTX
    GNDGND
    3V33V3

    在这里插入图片描述
    实际接线如下图
    在这里插入图片描述

    3. 通过串口传输数据

    按照上示连接好了之后,连接两台电脑,打开各自电脑的串口助手,并打开串口
    在这里插入图片描述
    在这里插入图片描述
    1. 选择一个文件进行传输
    这里我选择传输一张2.11Mb的jpg文件
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/4c3f75b2c2bf4fd2b8ce47f7c59e7482.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAdHlfc2o=,size_20,color_FFFFFF,t_70,g_se,x_1
    2. 计算理论传输时间
    在串口助手打开了文件之后,显示文件大小为2220595字节

    在这里插入图片描述
    根据之前给出的计算公式,理论传输时间为216秒
    在这里插入图片描述
    3. 实际传输对比

    开始传输后,发送端与接收端分别显示如下
    在这里插入图片描述
    在这里插入图片描述
    传输完成后

    在这里插入图片描述
    传输时,使用手机同步计时,实际的传输时间为4*60+31=271秒,比理论计算的216秒与系统给出的理论实践200秒都要长,说明实际上通过串口传输的速率没办法达到理论峰值。
    在这里插入图片描述

    三、总结

    本次实验通过两个usb to ttl在两台pc机之间进行了大文件的传输,并对文件大小进行预算,根据大小估算了理论计算时间,再将理论与实际时间进行对比,实验结果表明,串口的实际传输速率是要低于理论速率的。本次实验的过程总体来说还是比较顺利,接线也比较简单,但是其实背后的一些底层原理还没有那么清晰,所以以后还需要继续接着学习、动手实践。

    参考文献

    串口是怎样传输数据的
    什么是波特率,波特率怎么计算
    【转】波特率计算串口速度

    展开全文
  • 尽管比按字节(byte)传输的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。 串口通信中比较重要的参数包括波特率、数据位、停止位及校验位,通讯双方需要约定一致的数据格式才能正常收发...

    一、串口通信简介

    串口通信,顾名思义也就是利用串行接口进行通信。串行接口指串口按位(bit)发送和接收字节。尽管比按字节(byte)传输的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。

    串口通信中比较重要的参数包括波特率、数据位、停止位及校验位,通讯双方需要约定一致的数据格式才能正常收发数据。串行通讯根据通信双方的分工和信号传输方向可以进一步分为单工、半双工和全双工三种。在串口通信中,常用的协议包括RS-232、RS-422和RS-485。它们的主要区别在于其各自的电平范围不相同。

    二、串行通信的传输方向

    数据通信中,数据在线路上的传送方式(方向)可以分为:单工通信、半双工通信和全双工通信三种。

    1 单工(Simplex Communication )

    单工模式通信使用一根传输线,其数据传输是单向的,仅能沿一个方向,不能实现反向传输,即通信双方发送端和接收端的身份是固定的。通信双方中,一方固定为发送端,一方则固定为接收端。

    • 例子:早期的电视,广播,打印机

    2 半双工(Half Duplex Communication)

    半双工模式通信一般使用一根(或一对)传输线,数据可以沿两个方向传输,既可以发送数据又可以接收数据,但不能同时进行发送和接收,同一时刻只允许单方向传送。因此又被称为双向交替通信。数据传输允许数据在两个方向上传输,但是,在任何时刻只能由其中的一方发送数据,另一方接收数据。

    半双工模式收发两端都有发送器和接收器,通过收/发开关转接到通信线上。半双工通信中每端需有一个收发切换电子开关,若要改变传输方向,需由开关进行切换,通过切换来决定数据向哪个方向传输。由于要频繁切换信道方向,会产生时间延迟,故传输效率低些,但可以节约传输线路。半双工方式适用于终端与终端之间的会话式通信。

    • 例子:对讲机,RS485

    3 全双工(Full Duplex Transmission)

    全双工模式通信指数据由两根不同的数据线(可能还需要控制线、状态线、地线)传送,可以同时进行双向传输。即数据的发送和接收分流,通信双方都能在同一时刻进行发送和接收操作。从功能角度方面讲,全双工通信相当于两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。因此,通信系统的每一端都设置了发送器和接收器,来控制数据同时在两个方向上传送。

    与半双工模式相比,全双工可同时进行数据收发,且无需进行方向的切换,没有切换操作所产生的时间延迟。 显然,在其它参数都一样的情况下,全双工比半双工传输速度要快,信息传输效率要高。这对那些不能有时间延误的交互式应用(例如远程监测和控制系统)十分有利。

    • 例子:手机通话,RS422,RS232

    三、串行通信的错误校验

    在通信过程中往往要对数据传送的正确与否进行校验。校验是保证准确无误传输数据的关键。常用的校验方法有奇偶校验、代码和校验及循环冗余码校验。

    (1)奇偶校验

    在发送数据时,数据位尾随的1位为奇偶校验位(1或0)。

    (2)常用算法校验

    代码和校验是发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。

    (3)循环冗余校验

    这种校验是通过某种数学运算实现有效信息与校验位之间的循环校验,常用于对存储区的完整性、磁盘信息的传输校验等。

    1 奇偶校验

    奇偶校验指的是在发送数据时,利用数据中“1”的个数是奇数或偶数作为检测错误的标志。通常在数据位后面设置1位奇偶校验位(1或0),用它使这组代码中“1”的个数为奇数或偶数。奇校验时,数据中“1”的个数与校验位“1”的个数之和应为奇数;偶校验时,数据中“1”的个数与校验位“1”的个数之和应为偶数。接收学符时,接收端对数据位“1”的个数进行校验,若发现发送端结果与不一致,则说明传输数据过程中出现了错误。此时接收端可以向发送端发送请求,要求重新发送一遍数据。

    • 奇校验:此时奇偶校验位的作用就是保证所有数据位加奇偶校验位的所有比特位中值为1的比特位的个数为奇数。
      若数据位中共有奇数个值为1的比特位,则此时奇偶校验位的值为0。
      若数据位中共有偶数个值为1的比特位,则此时奇偶校验位的值为1。
    • 偶校验:此时奇偶校验位的作用就是保证所有数据位加奇偶校验位的所有比特位中值为1的比特位的个数为偶数。
      若数据位中一共有奇数个值为1的比特位,则此时奇偶校验位的值为1。
      若数据位中一共有偶数个值为1的比特位,则此时奇偶校验位的值为0。

    例子

    假设传输的数据位为01001100,如果是奇校验,则奇校验位为0(确保总共有奇数个1);如果是偶校验,则偶校验位为1(要确保总共有偶数个1)。

    优缺点

    奇偶校验的缺点很明显,首先,它对错误的检测概率大约只有50%。因为只有奇数个数据位发生变化能检测到,如果偶数个数据位发生变化则无能为力了。另外,每传输一个字节都要附加一位校验位,对传输效率有较大影响。因此,在高速数据通讯中很少采用奇偶校验。奇偶校验可以发现错误,但不能纠正错误,也就是说它只能告诉你出错了,但不能告诉你怎么出错了,一旦发现错误,只能重发。

    奇偶校验优点也很明显,它很简单,因此可以用硬件来实现,这样可以减少软件的负担。因此,奇偶校验也被广泛的应用着。

    2 常用算法校验

    常用算法校验是指发送端将所发数据块进行累加和校验异或校验,在数据块末尾附加一个字节的校验字符。接收端接收数据,同时对数据块(除校验字节外)进行不进位求和字节异或,将所得的结果与发送端的“校验和”进行比较,相符则无差错,否则即认为传送过程中出现了差错。

    例子-累加和校验
    累加和校验:
    要传输的数据为:01H、55H、D3H
    则进行不进位累加的校验和字节为:29H,即01H+55H=56H,56H+D3H=129H,舍去进位1,得29H。
    这里 29H 就是前三个字节的累加校验和。接收端收到全部数据后对前三个数据进行同样的累加计算,如果累加和与最后一个字节相同的话就认为传输的数据没有错误。

    异或就是对数据逐一异或计算(异或结果与下一个数据异或)。即接收端将所有字节(一般是两个16进制的字符)按位异或后,得到校验码后与发送端异或码的字符进行比较。相等即认为通信无错误,不相等则认为通信出错。

    优缺点

    累加和校验由于实现起来非常简单,也被广泛的采用。虽然其检错率优于奇偶校验,但这种校验方式的检错能力也较为一般,例如累加的其中一个字节多1,另一个字节少1,累加和不变,将原本是错误的通讯数据误判为正确数据。异或校验同理。累加和校验、异或校验也不能纠正错误。

    3 循环冗余校验

    这种校验是通过某种数学运算实现有效信息与校验位之间的循环校验,常用于对磁盘信息的传输、存储区的完整性校验等。这种校验方法纠错能力强,广泛应用于同步通信中。

    循环冗余码校验(Cyclical Redundancy Check, CRC)是利用除法和余数的原理来做错误侦测的。实际应用时,发送装置计算出CRC值并随数据一同发送给接收端RX,RX对收到的数据重新计算CRC并与收到的CRC值相比较,若两个CRC值不同,则说明数据通信出现了错误,该数据包应该舍弃不用。
    在远距离数据通讯中,为确保高效而无差错的传送数据,必须对数据进行校验控制,而CRC是对一个传送数据块进行校验,是一种非常高效的差错控制方法。目前,主流的CRC可以分为以下几个标准:CRC-12码;CRC-16码;CRC-CCITT码;CRC-32码。
    CRC-12码通常用来传送6-bit字符串。CRC-16及CRC-CCITT码则用来传送8-bit字符,其中CRC-16为美国采用,而CRC-CCITT为欧洲国家所采用。CRC-32码用途有限。
    在数据存储和数据通信领域,CRC无处不在:著名的通信协议X.25的FCS(帧检错序列)采用的是CRC/CCITT,ARJ/LHA等压缩工具软件采用的是CRC32,磁盘驱动器读写采用的日式CRC16,通常用到的图像存储格式GIF/TIFF等也是采用CRC作为检错手段的。

    四、传输速率与传输距离

    数据传输速率指通信线上传输信息的速度,有比特率和波特率两种表示方法。比特率也称为信号速率,是指单位时间内所传送的二进制位代码的有效位数,以每秒多少比特计算,即bit/s;波特率是指调制速率,是脉冲信号经过调制后的传输速率,以波特(Baud)为单位,通常用于表示调制器之间传输信号的速率。

    1 传输速率

    比特率:每秒传输的二进制位数,也称为信号速率,单位为比特每秒(bit/s,bps)。

    波特率:每秒传输的码元符号的个数(码元传输速率),也称为调制速率,单位是波特(B)。它是对符号传输速率的一种度量,它用单位时间内载波调制状态改变的次数来表示,1波特即指每秒传输1个符号。通过不同的调制方法可以在一个符号上负载多个比特信息。

    比特率与波特的关系
    即比特率在数值上和波特率有这样的关系:

    I = S ∗ l o g 2 N I=S*{log_2{N}} I=Slog2N

    其中I为比特率,S为波特率,N为每个符号承载的信息量(一个脉冲信号所表示的有效状态),而 l o g 2 N {log_2{N}} log2N以比特为单位。即波特率与比特率的关系:比特率=波特率*单个调制状态对应的二进制位数。
    一个以X波特传送信号的线路,其传送二进制数据的速率不一定是X比特/秒,因为每个码元符号需要通过几个比特来表示,所以运送一个符号等于运送了几个比特。在二进制中脉冲(二电平)只有两种状态0或1,即 n=“2”,也就是说,信号速率与调制速率是一致的。如果使用多电平脉冲信号传输信息,信号速率与调制速率就不一致了。例如,若使用0、1、2、3、4、5、6、7共8个电平级,则需要,即3个比特来表示一个信号值,因而这种条件下比特率将是波特率的3倍。(当用二进制位表示一个码元时与比特率相等)

    例如假设数据传送速率为120符号/秒(symbol/s)(也就是波特率为120Baud),又假设每一个符号为八相调制(单个调制状态对应3个二进制位),则其传送的比特率为(120symbol/s) * (3bit/symbol)=360bps。只有在每个符号只代表一个比特信息的情况、或一些简单的调制方式下,例如基带二进制信号调制方式等,波特率与比特率才在数值上相等。 具体而言, 两相调制(单个调制状态对应1个二进制位)的比特率等于波特率;四相调制(单个调制状态对应2个二进制位)的比特率为波特率的两倍;八相调制(单个调制状态对应3个二进制位)的比特率为波特率的三倍,依次类推。

    在串行通信中,单个调制状态对应的1个二进制位,因此比特率和波特率往往相同。可以用”波特率”来描述数据的传输速率,即每秒钟传送的二进制位数。它是衡量串行数据速度快慢的重要指标。典型的“波特率”是1200,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800,921600等。有时也用”位周期”来表示传输速率,位周期是波特率的倒数。

    举例:RS485/RS232
    假设目前“波特率”为9600,指每秒传送9600个码元符号,则此RS485/RS232的传信率计算为 :

    I = S ∗ l o g 2 N = 9600 ∗ l o g 2 2 I=S*{log_2{N}}=9600*log_2{2} I=Slog2N=9600log22=9600bit/s

    通信线上所传输的字符数据(代码)是逐位传送的,1个字符由若干位组成,每一位即是一个码元。因此每秒钟所传输的字符数(字符速率)和波特率是两种概念。常有人把RS232的N误以为是每个“符号”(symbol)所夹带的信息量,但实际上每个“位元”(bit)即为一个“符号”(symbol)。

    在串行通信中,所说的传输速率是指波特率,而不是指字符速率。
    如在异步串行通信中,传输速率是9600b,而每个字符格式包含10位(1个起始位、1个停止位、0个校验位、8个数据位),这时每秒钟传送的字符数:9600/(1+8+0+1)=960个。

    2 传输距离与传输速率的关系

    串行通信直接传送串行信息位流的最大距离与传输速率和传输线的电气特性有关。通信速率和通信距离这两个方面是相互制约的,降低通信速率,可以提高通信距离。

    串行通信中,数据位信号流在信号线上传输时,要引起畸变,畸变的大小与以下因素有关:

    波特率——信号线的特征(频带范围)
    传输距离——信号的性质及大小(电平高低,电流大小)
    当畸变较大时,接收方出现误码。
    在规定的误码率下,当波特率、信号线、信号的性质及大小一定时,串行通信的传输距离就一定。为了加大传输距离,必须加调制解调器。

    当传输线使用每0.3m(约1英尺)有50PF电容的非平衡屏蔽双绞线时,传输距离随传输速率的增加而减小。当比特率超过1000 bps时,最大传输距离迅速下降,如9600 bps时最大距离下降到只有76m(约250英尺)。

    串口通讯的距离

    经实测,液晶显示屏控制 系统的RS232串行口在通讯波特率为28800bit/s时能够稳定传输达300米以上(传输介质为1箱五类线);当通讯距离大于 300米时,选择RS485通讯接口的液晶显示屏控制系统,此时只须在计算机的RS232串口端加配一个RS232/485转换器即可。

    115200bps最好的距离在30-50米之间(和线、232芯片有关),再远就有误码啦。15米还是很容易超的。232谁也不敢用300米的。

    传输电缆长度

    由RS-232C标准规定在码元畸变小于4%的情况下,传输电缆长度应为50英尺,其实这个 4%的码元畸变是很保守的,在实际应用中,约有99%的用户是按码元畸变10-20%的范围工作的,所以实际使用中最大距离会远超过50英尺。

    传输距离

    由设备可提供端口的不同,故数据传输距离也不同。普通的RS232是常见的设备端口,其连接距离只有15米左右,如果连线设备距离相当远,则无法在使用RS232。采用RS424的设备,它的连接距离可达1000米。但当多个设备都是远距离时,给每个设备拉一条线会相当不方便,于是RS485便成为首选。RS485接口支持多个设备同时挂在一根导线上,它的总连线距离也可达1000米,而且一路上所有的设备都可以连接其上,相当方便。但它有一个限制:必须是半双工通信方式,即在同一时刻只能有一个设备进行数据发送,而其他设备只能接收。要保证这个条件必须依靠软件。

    3、发送/接收时钟

    在串行传输过程中,二进制数据序列是以数字信号波形的形式出现的,如何对这些数字波形定时发送出去或接收进来,以及如何对发/收双方之间的数据传输进行同步控制的问题就引出了发送/接收时钟的应用。

    在发送数据时,发送器在发送时钟(下降沿)作用下将发送移位寄存器的数据按串行移位输出;在接收数据时,接收器在接收时钟(上升沿)作用下对来自通信线上串行数据,按位串行移入移位寄存器。可见,发送/接收时钟是对数字波形的每一位进行移位操作,因此,从这个意义上来讲,发送/接收时钟又可叫做移位始终脉冲。另外,从数据传输过程中,收方进行同步检测的角度来看,接收时钟成为收方保证正确接收数据的重要工具。为此,接收器采用比波特率更高频率的时钟来提高定位采样的分辨能力和抗干扰能力。
      
    发送/接收时钟频率与波特率的关系:发/收时钟频率 =n*(发/收波特率 )

    4、波特率因子

    在波特率指定后,输入移位寄存器 / 输出移位寄存器在接收时钟 / 发送时钟控制下,按指定的波特率速度进行移位。一般几个时钟脉冲移位一次。要求:接收时钟/ 发送时钟是波特率的 16 、 32 或 64 倍。波特率因子就是发送/接收 1 个数据( 1 个数据位)所需要的时钟脉冲个数,其单位是个/位。如波特率因子为 16 ,则16 个时钟脉冲移位 1 次。 例:波特率 =9600bps ,波特率因子 =32 ,则接收时钟和发送时钟频率 =9600 × 32=297200Hz 。

    参考:
    【1】https://baike.baidu.com/item/%E6%B3%A2%E7%89%B9%E7%8E%87/2153185?fr=aladdin#reference-[3]-119333-wrap
    【2】https://baike.baidu.com/item/%E7%A0%81%E5%85%83/10525003
    【3】http://mayer.spaces.eepw.com.cn/articles/article/item/59707

    展开全文
  • 【嵌入式】电脑之间串口传输文件

    千次阅读 2021-11-19 15:08:39
    本实验主要练习两台电脑之间如何通过串口传输文件一、 串口通信简介1.串口通信概念2.串口如何连接3.计算传输时间二、实验要求及过程1.实验题目2.实验过程三、 结果分析 一、 串口通信简介 1.串口通信概念 串口通信...
  • 串口DMA传输模式

    2021-10-28 16:09:53
    DMA传输模式前言一、DMA简介(一)DMA系统框图(二)DMA传输通道(三)DMA传输模式1.外设与存储器之间2.存储器与存储器之间3.小结二、使用DMA配置1.打开USART1及DMA模式2.读入数据总结 前言 DMA(Direct Memory ...
  • 串口传输文件

    2021-11-08 22:12:46
    目录串口与PC传送文件发送文件总结 串口与PC传送文件 使用软件sscom下载链接...传输的文件如果数据不压缩,波特率等于每秒钟传输的数据位数,如果数据进行了压缩,那么每秒钟传输的数据位数通常大于调制速率。 ...
  • 如果数据不压缩,波特率等于每秒钟传输的数据位数,如果数据进行了压缩,那么每秒钟传输的数据位数通常大于调制速率,使得交换使用波特和比特/秒偶尔会产生错误。 波特率是指数据信号对载波的调制速率,它用单位时间...
  • 什么是串口服务器就是一种通过网络连接两个或多个串口设备的联网设备。它可以让我们使不在受到物理电缆的长度限制,无论它们位于世界的任何地方,都可以通过以太网连接串口设备。通过使用串口连接的方法,设备可以...
  • 串行接口 (Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。...
  • 这里写目录标题一、实验要求二、I2C总线通信协议(一)概念(二)I2C总线特征(三)...1)解释什么是“软件I2C”和“硬件I2C”? (阅读野火配套教材的第23章“I2C–读写EEPROM”原理章节) 2)阅读AHT20数据手册,编程
  • 前言:平时我们进行c语言编程的时候会经常用到printf函数进行打印输出,来调试代码。可是这个printf函数C库已经帮我们实现好了,...1、什么是串口通信?串口通信(Serial CommunicaTIon),是指外设和计算机间,通过数...
  • 两个串口之间传输文件

    千次阅读 2021-11-12 22:45:15
    准备两个USB TO TTL和杜邦线若根,将两个USB TO TTL的RX,TX引脚交叉连接,并将两个USB接口接上一台笔记本电脑(模拟两台计算机之间的串口传输)。 二.传输文件 利用可以传输文件的串口调试助手(在这里我采用的是...
  • lflag: ICANON 使能规范输入,否则使用原始数据(本文使用) ECHO 回送(echo)输入数据 ECHOE 回送擦除字符 ISIG 使能SIGINTR,SIGSUSP, SIGDSUSP和 SIGQUIT 信号 c_iflag: IXON 使能输出软件控制 IXOFF...
  • 什么是串口WIFI模块

    千次阅读 2021-01-17 17:42:57
    展开全部串口WiFi模块多是...串口WiFi模块是多种WiFi模块中的一类,功能是将串口或TTL电平转换为符合Wi-Fi无线网络通信标准的数据传输模块。串口WiFi模块一般会集成射频电路、MAC地址、WIFI驱动和协议、无线安全协议...
  • 并行传输和串行传输的区别是什么

    千次阅读 2021-06-27 10:23:17
    什么是串行通信串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与...
  •  波特率是一个电子信号上的术语,用于描述信道的数据传输速度。所谓信道,可以是无线的,也可以是有线的,说白了就是两个东西之间传输数据。 波特率通常单位是bit/s,也就是 二进制位/秒。因为一个字节是8个bit,而...
  • RS232串口通信的传输格式和接收过程

    千次阅读 2021-07-26 01:29:45
    描述串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。大多数计算机包含两个基于RS232的串口串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS...
  • 4、实验结果 Simulnk发送,STM32接收 1、选择3个常值,类型为uint8,选择MUX,输入为3port,连线 2、选择Serial Send模块,选择好串口后连线即可 3、STM32端设置好接收缓存数组,下载程序 u8 rectemp[3];...
  • 描述串口通信简介串口是计算机上一种...串口通信结构串口通信是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本...
  • 串口通信详解

    2021-10-09 13:23:56
    一、串口通讯简介 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和...典型地,串口用于ASCII码字符的传输。通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,端口能够在一根
  • 文章目录 一、汉字编码 1、国标码 2、 区位码 3、机内码 4、点阵字库 二、利用opencv 1准备工作 2、代码实现 3、编译运行 4、运行效果 三、串口传输文件的练习 1、知识补充 2、实验过程 四、总结 一、汉字编码 学习...
  • 串行通信:串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的远距离通信。 拿...
  • 上篇博文虽然实现了串口数据连续接收,但是整体代码写的不理想。下面参考小梅哥的代码风格对我的代码进行大整改!
  • 串口传输文件练习

    2021-11-13 17:12:41
    用两个串口,将它们的TXD,RXD交叉连接,实现数据的互传。 连接效果如下: 接着打开两个串口助手,分别选择不同的串口,尝试通信 通信成功。 二、大文件传输 准备一张图片 默认速度传输:115200...
  • 题目:利用单片机串口实现甲乙两级的数据传输。 要求: ①甲机连续发送0-F,共记16个字符,并显示再数码管上; ②乙机接受甲机内容并用数码管显示后回传; ③甲机接收到乙机回传内容后与当前内容相比较,若一致则...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,772
精华内容 11,908
关键字:

串口传输的是什么信号