如何才能完好的接收c51单片机传输来的数据,为什么我接受到的全是乱码

如何才能完好的接收c51单片机传输来的数据,为什么我接受到的全是乱码,求解答.

1,串口工作模式有误,比如波特率参数错误
2,单片机传过来的并不是文本数据,而你用文本模式显示。

  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7788298
  • 我还给你找了一篇非常好的博客,你可以看看是否有帮助,链接:C51源程序中中断函数不能进行参数传递,中断函数中包含任何参数声明导致变易出错,但网上都说可以。可能是KEIL改进了。还要注意变量声明和定义的区别。定义包含声明,声明不一定是定义
  • 除此之外, 这篇博客: 单片机_第4章 单片机的C51语言中的 定义一个变量的完整格式(变量具有4大要素):〔存储种类〕数据类型〔存储类型〕变量名; 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 〔存储种类〕
    • 变量定义时还需考虑变量的“作用域”问题。
    • 为提高变量存储效率,比较科学的做法应该是:
      • ①对于仅有当前使用价值的变量,可以让它用完后“自动”释放占用的存储单元,以便编译器重新进行变量存储空间分配;——auto
      • ②对于具有长期使用价值的变量,可以让它处于“静态”保护下,在程序运行期间都不释放存储单元;——static
      • ③对于需要在多个程序或函数中传递数据的变量,可以让它只在一处进行定义,而在其它程序或函数中声明它的“外部”属性,从而实现该变量的数据共享;——extern
      • ④对于需要频繁改变其值的变量,可让其数值保存在CPU的“寄存器”中,避免反复访问内存,从而获得较高的执行效率。——register
    • 变量的存储类型有4种:
      • 1、自动型(auto)。
        • 具有auto属性的变量称为自动型变量。自动型变量的作用域是在定义该变量的函数体或语句组内。当函数调用结束或语句组执行完毕时,自动型变量所占用的存储单元就被释放。由于存储单元中的值是随机的,因此自动型变量在赋初值前的值也是随机的。自动型是“存储种类”的默认选项,如果变量定义时“存储种类”项省略,则变量被默认为是自动型的。
      • 2、静态型(static)。
        • 具有static属性的变量称为静态型变量。静态型变量的作用域是定义它的函数体、程序文件或语句组内。静态型变量具有变量的隐藏性、存储持久性和默认0初值3个特点。
        • 如果希望变量在离开作用域后仍能保持它已经获得的数值不丟失,或者希望变量无法被作用域外的其它同名变量所使用,或者希望变量虽经定义但缺省赋初值时能默认为0,就可在变量定义时用static进行声明。
      • 3、外部型(extern)。
        • 具有extern属性的变量称为外部型变量。如果变量的定义与使用不在同一个作用域内,则用extern声明后就能将原作用域扩展到声明所在的位置,从而将变量值带到新的作用域内。extern的这一扩展性与static的隐藏性恰好相反。变量做extern声明后可分配固定的存储单元,并在程序的整个执行期内始终有效。
      • 4、寄存器型(register)。
        • 具有register属性的变量称为寄存器型变量。如果变量在使用中需要频繁地与内存进行数据交换,可以通过register定义将变量的存储单元指定为寄存器。但是随着编译器技术不断优化,现在编译器已能将数据交换过于频繁的变量自动放入寄存器中,因而进行register声明的必要性已不大了。
    • 注意
      • auto,static和register关键词需要在变量定义的同时进行使用,不能单独使用
        • 因此下面的用法是不对的:
          • int a; (先定义整型变量a)
          • static a; (企图再对a声明为静态变量)
        • 这样做会被编译器认为是“重新定义”。正确的用法应该是:static int a;
      • 但是,extern却是可以单独进行声明的,它可对已定义过的变量进行作用域扩展,例如:
        • int b;(在另一程序文件或函数中定义了变量b)
        • extern b;(将变量b的作用域扩展至此,允许省略变量b的int类型)
      • 变量的定义和变量的声明问题
        • 实际应用中这两者常常被不加区别的随意使用,这是不严格的,因为两者间是有区别的。
        • 变量定义既涉及到变量特性的约定,也涉及到存储单元的分配问题。
        • 变量声明则是仅指出变量的特性,不涉及存储单元的分配问题。
        • 例如上面介绍过的“int a;”称为变量定义,而“extern b;”则称为变量声明。
      • 全局变量与局部变量问题
        • 根据C51规则,变量定义语句放置的位置决定了变量的作用域,其中放在程序开始处(即所有函数前面)的称为全局变量,而放在函数内部的称为局部变量。
        • 全局变量的作用域是整个源程序范围,变量值可在程序运行期间始终有效,而局部变量值仅在函数调用期间有效,调用结束后就会失效。
        • 为了合理利用存储资源,需要根据情况灵活采用全局变量或局部变量,一般情况下应尽量选用局部变量。
  • 数据类型
    • C51使用的数据类型 = 标准C语言传承的 + C51特有的
    • (一)由标准C语言传承的数据类型
      • 数据类型用于表示数据存放格式(有符号数类型可以忽略signed标识符)

      • 整型数据、字符型数据和浮点型数据
        • 1、整型变量与整型常量
        • 2、字符型变量与字符型常量
        • 3、浮点型变量与浮点型常量
    • (二)C51特有的数据类型
      • bit型、sfr型和sbit型
      • 1、bit型变量
        • 可以但不限于在位寻址区开辟内存空间,作状态变化
        • 51单片机中有许多可以按位(bit)进行读写操作的存储单元,如片内RAM中位地址为00~7FH的128个位存储单元。每个位存储单元都可存放0或1两个位型常量。与这些位存储单元相对应的变量称为位型变量或bit型变量。
        • 位型变量的一般定义形式也与整型变量基本相同,即类型说明符 变量名〔=0或1〕;例如:bit abc =1;(指定变量abc为位型变量,初值为1)
      • 2、sfr型变量
        • 80C51单片机内部有21个特殊功能寄存器(SFR),除了DPTR为16位寄存器外(在SFR中,DPTR也被分成了DPH和DPL两个8位的)(PC为16位寄存器但是不属于SFR),其余都是8位寄存器,每个SFR都有特定的字节地址,部分SFR中还有独立的位地址。
        • sfr型变量的一般定义形式为:类型说明符 变量名=8位地址常量;
          • 类型说明符:
            • 8位SFR变量的sfr,16位SFR变量的sfr16
            • 8位地址常量是指有意义的SFR字节地址
            • 例如:
              • sfr P1 = 0x90;//指定变量P1为sfr型变量,对应地址为0x90
              • sfr PSW = 0xd0; //指定变量PSW为sfr型变量,对应地址为0xd0
              • sfr16 DPTR = 0x82; //指定DPTR为sfr16型变量,即DPL=0x82,DPH=0x83
      • 3、sbit型变量
        • “相对位置”是指相对于已定义过SFR名称或可位寻址字节地址的位置,其中0表示最低位,以此类推。

        • 如前所述,sbit是用于定义SFR中具有位地址变量的类型说明符,变量定义可以有以下3种不同的用法:
          • 第1种(绝对位地址):sbit 位变量名=位地址;
            • 例如, sbit CY = 0xD7;
          • 第2种(相对位地址):sbit 位变量名=可位寻址的SFR字节地址^相对位置
            • 例如,sbit CY = 0xD0^7;
          • 第3种(相对位位置):sbit 位变量名=可位寻址变量^相对位置
            • 例如,sbit CY = PSW^7;
      • 还需要注意几点:
        • ①虽然bit和sbit定义的都是位型变量,但两者还是有很大区别的:
          • bit型变量的位地址是由编译器为其随机分配的(定义时不能用户指定),位地址范围是在片内RAM的可位寻址区(bdata区)中;
          • sbit型变量的位地址则是由用户指定的,位地址范围是在可位寻址的SFR单元内(利用bdata限定变量存储类型后可将位地址范围扩大到bdata区)。
        • ②sfr型变量和sbit型变量都必须定义为全局变量,即必须在所有C51函数之前进行定义,否则就会编译出错。
        • 程序中如果使用了头文件reg51.h后,原先定义P1变量的语句(sfr P1=0x90;)便可省略。但由于头文件reg51.h中并未对P0~P3寄存器中的位单元(如P1.0)进行sbit定义,因此程序中还需重新定义如p1_0的sbit型变量。
        • bit和unsigned char这两种数据类型都可以直接支持单片机机器指令,因此代码的执行效率最高,编程时应尽量选用bit和unsigned char这两种变量。
          • signed char虽然也只占有一个字节,但CPU需要进行额外的操作来测试代码的符号位,这无疑会降低代码效率。
          • 使用浮点型变量时,编译系统将调用相应的库函数来保证运算精度,这将明显增加运算时间和程序代码长度,因此,不是十分必要时应尽量避免使用float数据类型。
      • C51常用数据类型一览表

  • 〔存储类型〕
    • 为了合理使用51单片机的存储空间,需要进一步细化存储区域的组成,为此C51将3个物理存储空间细分成6个存储类型区。

    • 片内低128B RAM空间被划分成data和bdata两个存储区,8052型单片机专有的高128B RAM被作为idata存储区,片内外统一ROM空间被作为code存储区,片外RAM空间被划分成xdata和pdata两个存储区。
    • 若省略,则默认为data区(此时位于SMALL编译模式下)

      • 实际应用中,用户对单片机存储器的需求差别很大,为此,C51编译器中设立了3种编译模式供用户选择。
        • 在SMALL编译模式下,如果变量定义语句中省略了存储类型参数,则系统会自动默认采用data存储类型。同理,COMPACT编译模式和LARGE编译模式时的默认存储类型分别是pdata和xdata。
          • 例如,在SMALL编译模式下,变量a的定义语句char a;等价于char data a;。而在LARGE编译模式下,变量a的定义语句char a;则等价于char xdata a;。
        • 编译模式可以通过µVision3工程配置窗口的“Target”页进行指定。
    • 不同存储区各有特点,适合不同类型的变量。(注意:idata区)

    • 由此可见,变量在定义时,只有将其数据类型和存储类型的信息都展现在变量定义式中才能保证编译器顺利工作。
  • 变量名
    • C51语言中规定:
      • 变量名可以由英文字母、数字和下划线3种字符组成;
      • 第1个字符必须为字母或下划线(即不能为数字);
      • 变量名长度无统一规定(视编译系统而定),一般为不超过8个字符,超过部分有可能被编译系统舍弃。
      • 例如:sum,_total,month,Student,lotus_3,BASIC,li_ling都是合法的变量名。M.D.John,¥123,3D64,a>b都是不合法的变量名。
    • 使用变量名时还应注意:
      • 1、编译系统会将大写字母和小写字母认为是两个不同的字符,即变量名是大小写敏感的,如SUM和sum,习惯上变量名用小写字母表示,常量标识符用大写字母表示。(汇编语言不敏感)
      • 2、在选择变量名时,最好做到“见名知意”,即选用有一定含意的英文单词(或其缩写)作变量名。
      • 3、编译系统规定的关键词不得作为变量名,其中包括标准C语言的32个关键字和C51语言扩展的21个新关键字。

      • 强调:头文件中定义的变量(SFR)都是大写的,若程序采取小写变量则需要重新定义。
  • 以下回答由chatgpt基于相关博客总结生成:

    解决方案:

    要正确接收和解析C51单片机传输的数据,可以按照以下步骤进行操作:

    1. 理解C51单片机串口通信协议。C51单片机通常使用UART(通用异步收发器)作为串口通信接口。根据C51单片机的规格和使用的串口配置,了解串口相关设置,如波特率、数据位、停止位和校验等参数。这些参数在接收端必须与C51单片机的配置一致。

    2. 配置串口接收。使用所选编程语言的串口库或API来打开串口并设置其参数,以便接收C51单片机传输的数据。确保将串口的接收缓冲区设置为足够大,以存储完整的传输数据。

    3. 读取接收数据。通过调用串口库或API中的读取函数来从串口接收缓冲区中读取数据。读取的数据将以字节形式返回。

    4. 解析接收数据。根据C51单片机传输的数据格式,解析接收到的字节数据。这可能包括识别数据头、解析数据字段和校验数据的完整性。根据具体的数据格式,可以使用字符串拆分、位操作或其他解析方法来提取所需的信息。

    5. 处理解析的数据。根据业务需求对解析得到的数据进行处理。这可能涉及到将数据存储到数据库、进行计算、显示到界面或与其他系统进行集成等操作。

    以下是一个示例使用Python编程语言的代码片段,演示如何通过串口接收并解析C51单片机传输的数据:

    import serial
    
    # 打开串口
    ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
    
    # 读取并解析数据
    while True:
        data = ser.read(1)  # 从串口读取一个字节的数据
        if data:  # 如果接收到数据
            # 解析数据的逻辑
            # 比如,如果数据格式为ASCII字符串,可以通过ord函数将字节转换为整数,然后处理该整数
            value = ord(data)
    
            # 处理解析得到的数据的逻辑
            # 比如,可以将数据存储到数据库、进行计算或显示在界面上
    
            print("Received data:", value)
    

    请根据实际情况调整上述代码,根据C51单片机配置的串口参数以及数据格式进行相应设置和解析操作。

    注意:具体的代码实现方式将根据所选的编程语言和开发环境而有所不同。此处提供的示例代码仅供参考,需根据实际情况进行调整。此外,还可以使用其他编程语言和工具,如C/C++、Java、Arduino等,来实现串口接收和解析的功能。