精华内容
下载资源
问答
  • bcd码转换十进制 bcd码怎么转换为十进制
    千次阅读
    2021-05-22 18:26:35

    bcd码转换成十进制 bcd码怎么转换为十进制

    BCD码的运算规则:BCD码是十进制数,而运算器对数据做加减运算时,都是按二进制运算规则进行处理的。这样,当将 BCD码传送给运算器进行运算时,其结果需要修正。修正的规则是:当两个BCD码相加,如果和等于或小于 1001(即十进制数9),不需要修正;如果相加之和在 1010 到1111(即十六进制数0AH~0FH)之间,则需加 6 进行修正;如果相加时,本位产生了进位,也需加 6 进行修正。这样做的原因是,机器按二进制相加,所以 4 位二进制数相加时,是按“逢十六进一”的原则进行运算的,而实质上是 2 个十进制数相加,应该按“逢十进一”的原则相加,16 与10相差 6,所以当和超过 9或有进位时,都要加 6 进行修正。下面举例说明。

    【例 1.3】 需要修正 BCD码运算值的举例。

    (1) 计算 5+8;(2) 计算 8+8

    解:(1) 将 5 和 8 以 8421 BCD输入机器,则运算如下:

    0 1 0 1

    +) 1 0 0 0

    1 1 0 1 结果大于 9

    +) 0 1 1 0 加 6 修正

    1 0 0 1 1 即13 的 BCD码

    结果是 0011,即十进制数3,还产生了进位。5+8=13,结论正确。

    (2)将8以8421 BCD输入机器,则运算如下:

    1 0 0 0

    +)1 0 0 0

    1 0 0 0 0 结果大于9

    +)0 1 1 0 加6修正

    1 0 1 1 0 16的BCD码

    结果是0110,即十进制的6,而且产生进位。8+8=16,结论正确。

    微机原理代码: (AL=BCD 5,BL=BCD 8) 设AH=0,则

    ADD AL,BL

    AAA

    结果为 AX=0103H,表示非压缩十进制数,CF=1,AF=1,AH=1,AL=3

    使用AAA指令,可以不用屏蔽高半字节,只要在相加后立即执行AAA指令,便能在AX中得到一个正确的非压缩十进制数

    在读写DS1302时需要把读写数据BCD码转换成十进制

    //*****************************************************************

    //bcd hex //此函数用于将8421BCD码转换为十进制数,从函数参数可以看出此BCD码是由两位十进制数组成的。BCD码是用二进制数对十进制数的各个位数进行编码,比如十进制数58,那么转换为BCD码为0x58,356对应BCD码就是0x356。注意这是编码不是数进制间的转换,他们之间不存在等价关系。只是进行编号,为了方便对编号后的数据用十六进制数表示。对应编码规则如下:

    十进制数---8421BCD码----编码后用等价的十六进制数表示

    0-----------0000----------0x0

    1-----------0001----------0x1

    2-----------0010----------0x2

    3-----------0011----------0x3

    4-----------0100----------0x4

    5-----------0101----------0x5

    6-----------0110----------0x6

    7-----------0111----------0x7

    8-----------1000----------0x8

    9-----------1001----------0x9

    知道了编码规则,那么将2位8421bcd码编号的数,还原为十进制数也就方便了。函数参数是一个字节那么决定了此8421BCD码是两位码即高四位是一个码值、低四位是一个码值,将高四位乘以10加上低四位码值就得到了十进制数。

    byte bcd2_hex(byte val)

    {

    byte i;

    i = val&0x0f; //按位与,i得到低四位数。

    val >>= 4; //右移四位,将高四位移到低四位的位置,得到高四位码值。

    val &= 0x0f; //防止移位时高位补进1,只保留高四位码值

    val *= 10; //高位码值乘以10

    i += val; //然后与第四位码值相加。

    return i; //将得到的十进制数返回

    }

    //*****************************************************************

    //这个应该是一个类似I2C协议的字节写操作。

    static void DS1302_WriteByte(byte val)

    {

    byte i;

    //MinCardClk(0); //stop clk

    //Sys_SetCpuClk(clockdiv1);

    for(i = 0; i < 8; i++) //通过循环将1字节也即8位二进制数送给i2c数据线。

    {

    if(val&0x01)DS1302_SDA_W(1); //如果此位是1,那么送给数据线1

    else DS1302_SDA_W(0); //如果是0,那么给数据线0

    DS1302_SCK(0); //时钟线置0也即拉低

    DS1302_SCK(1); //时钟线置1,通过这两个动作时钟线产生一个从低到高的跳变,作用是通知从器件取走数据线上的数据。

    val >>= 1;// FOR DELAY AND SHIFT //右移数据,接着发送下一位数据,数据是从低位到高位发送。

    }

    //DS1302_SCK(0);

    //Sys_SetCpuClk(clockdiv0);

    //MinCardClk(1); //start clk

    }

    //*****************************************************************

    //同理i2c读字节

    static byte DS1302_ReadByte(void)

    {

    byte i,val;

    //MinCardClk(0); //stop clk

    //Sys_SetCpuClk(clockdiv1);

    val=0;

    DS1302_SDA_W(1);

    for(i = 0; i < 8; i++) //循环从数据线上读取8位数据,然后凑成一字节。

    {

    DS1302_SCK(1);

    DS1302_SCK(0); //时钟一个从高到低的跳变,通知从器件将数据放到数据线上。

    val >>= 1; //接收完1位后右移数据,准备接收下一位,这里也是从低位到高位接收数据。

    if(DS1302_SDA_R())val |= 0x80; //如果是1那么与0x80或后就得到了1,如果是0,就不用管了因为在移位时直接补的是0.

    }

    //Sys_SetCpuClk(clockdiv0);

    //MinCardClk(1); //start clk

    return val;

    }

    一下是汇编的:

    re: asm

    BCD2BIN:

    ; INPUT:  R3:R2 -- BCD

    ; OUTPUT: R5:R4 -- BIN

    ; USE: A, B, PWS

    MOV A, R2

    CALL BCD_BYTE2BIN

    MOV R4, A

    MOV A, R3

    CALL BCD_BYTE2BIN

    MOV B, #100

    MUL AB

    ADD A, R4

    MOV R4, A

    CLR A

    ADDC A, B

    MOV R5, A

    RET

    BCD_BYTE2BIN:

    ; 10*Y + X = (16*Y + X)-6*Y = 250 * Y + (16*Y + X) - 256 * Y

    MOV R5, A

    ANL A, #0F0H

    SWAP A

    MOV B, #250

    MUL AB

    ADD A, R5

    RET

    更多相关内容
  • 已知一只包含0和1的二进制数,长度不大于10,将其转换为十进制并输出。 输入描述 输入一二进制整数n,其长度不大于10 输出描述 输出转换后的十进制数,占一行 样例输入 110 样例输出 6 solution:  很多学过C...
  • 2、两个十六进制的byte需要组合成一个十进制,比如高位:0x01,低位:0x78 组合成0x0178转十进制 解决办法 /** * byte转为十进制int * @param bytes * @return */ public static int byt...

    在模拟modbus通信过程的时候,需要有如下转换过程

    1、byte[]数组中存的是十六进制需要转十进制

    2、两个十六进制的byte需要组合成一个十进制,比如高位:0x01,低位:0x78  组合成0x0178转十进制

    解决办法

        /**
    	 * byte转为十进制int
    	 * @param bytes
    	 * @return
    	 */
    	public static int byte2int(byte bytes){
    		// 将byte转换为8位二进制字符串 依赖 commons-lang-x.x.jar包
    		String binaryString = StringUtils.leftPad(Integer.toBinaryString(bytes & 0xff), 8, '0');
    		// 将二进制字符串转换为十进制整数值
    		int value = Integer.parseInt(binaryString, 2);
    		return value;
    	}
    	
    	/**
    	 * 两个十六进制转为十进制
    	 * @param b1 十六进制低位
    	 * @param b2 十六进制高位
    	 * @return
    	 */
    	public static int byteToInt(byte b1,byte b2){
    		int deci = (b1|b2<<8);
    		return deci;
    		
    	}
     

     

    欢迎关注微信公众号,公众号的好处是可以持续保持联系。

     

     

    展开全文
  • 二进制如何转换为十进制?

    千次阅读 2021-06-19 05:54:00
    二进制到十进制数字转换使用加权列来标识数字的顺序以确定数字的最终值将二进制转换为十进制(base-2到base-10) )数字和背面是一重要的概念,因为二进制编号系统构成了所有计算机和数字系统的基础。十进制或...

    二进制到十进制数字转换使用加权列来标识数字的顺序以确定数字的最终值

    将二进制转换为十进制(base-2到base-10) )数字和背面是一个重要的概念,因为二进制编号系统构成了所有计算机和数字系统的基础。

    十进制或“denary”计数系统使用Base-of-10编号系统,其中数字中的每个数字都取10个可能值中的一个,称为“数字”,从 0 到 9 ,例如。 213 10 (二百一十三)。

    但是,除了10位数(0到9)之外,十进制编号系统还具有加法运算( + ),减法( - ),乘法(×)和除法(÷)。

    在十进制系统中,每个数字的值都比其前一个数字大十倍,这个十进制数字系统使用一组符号 b ,以及一个基数 q ,确定一个数字内每个数字的权重。例如,六十分之六的权重低于六百分之六。然后在二进制编号系统中,我们需要一些方法将十进制转换为二进制以及从二进制转换为十进制。

    任何编号系统都可以通过以下关系总结:

    N = b i q i

    where:

    N 是一个实数正数

    b 是数字

    是基数值

    和整数( i )可以是正数,负数或零

    N = b n q n ... b'的子> 3 q 3 + b 2 q 2 + b 1 q 1 + b 0 q 0 + b -1 q -1 + b -2 q -2 ... etc。

    十进制编号系统

    在十进制中, base-10(den)或denary编号系统,当我们沿着从右到左的数字移动时,每个整数列具有单位,数十,数百,数千等的值。在数学上,这些值写为10 0 ,10 1 ,10 2 ,10 3 等。然后每个位置在小数点左边表示增加的正幂为10.同样,对于小数,当我们从左向右移动时,数字的权重变得更负,10 -1 ,10 -2 ,10 -3 等

    所以我们可以看到“十进制编号系统”的基数为10或 modulo-10 (有时称为MOD-10),十进制系统中每个数字的位置表示该数字的大小或重量为 q 等于“10”(0到9)。例如,20(二十)与说2 x 10 1 相同,因此400(四百)与说4 x 10 2 相同。

    任何十进制数的值将等于其数字之和乘以各自的权重。例如: N = 6163 10 (六千一百六十三)十进制格式等于:

    6000 + 100 + 60 + 3 = 6163

    或者可以写出反映每个数字的权重:

    (6×1000)+(1×100)+(6×10)+(3×1)= 6163

    或它可以用多项式形式写成:

    (6×10 3 )+(1×10 2 )+(6× 10 1 )+(3×10 0 )= 6163

    在此十进制编号系统示例中,最左边的数字是最高有效数字或MSD,最右边的数字是最低有效数字或LSD。换句话说,数字 6 是MSD,因为它的最左侧位置承载的权重最大,而数字 3 是LSD,因为它的最右侧位置承载的权重最小。

    二进制编号系统

    二进制编号系统是所有基于数字和计算机的系统中最基本的编号系统,二进制数遵循相同的设置规则作为十进制编号系统。但是与使用10的幂的十进制系统不同,二进制编号系统使用2的幂,给出从base-2到base-10的二进制到十进制的转换。

    数字逻辑和计算机系统仅使用两个用于表示条件,逻辑电平“1”或逻辑电平“0”的值或状态,并且每个“0”和“1”被认为是2的基数(bi)中的单个数字或“二进制编号系统“。

    在二进制编号系统中,二进制数字如 101100101 用字符串”1“和”0“表示,每个数字沿字符串从右到左的值是前一个数字的两倍。但由于它是二进制数字,因此它只能具有“1”或“0”的值,因此 q 等于“2”(0或1),其位置表示其重量字符串。

    由于十进制数是一个加权数,从十进制转换为二进制(基数10到基数2)也会产生加权二进制数,右边最多位为最低有效位或LSB,最左边的位是最高有效位或MSB,我们可以代表这个:

    二进制数的表示

    MSB

    二进制数字

    LSB

    2 8

    2 7

    2 6

    2 5

    2 4

    2 3

    2 2

    2 1

    2 0

    256

    128

    64

    32

    16

    8

    4

    2

    1

    我们在上面看到,在十进制数系统中,每个数字从右到左的权重增加了10倍。在二进制数系统中,权重如图所示,每个数字增加了一个因子 2 。然后第一个数字的权重为 1 ( 2 0 ),第二个数字的权重为 2 ( 2 1 ),第三个是 4 的重量( 2 2 ) ,第四个是 8 ( 2 3 )的权重,依此类推。

    例如,转换二进制到十进制数字将是:

    十进制数字值

    256

    128

    64

    32

    16

    8

    4

    2

    1

    二进制数字值

    1

    0

    1

    1

    0

    0

    1

    0

    1

    加在一起在由“ 1 ”表示的位置从右到左的所有十进制数值给出:(256)+(64)+(32)+(4)+(1)= 357 10 或三百五十七作为十进制数。

    然后,我们可以通过查找二进制的十进制等效值将二进制转换为十进制数字数组 101100101 2 并将二进制数字扩展为基数为 2 的系列,其等效值为 357 10 十进制或否定。

    请注意,在数字转换系统中,“下标”用于表示相关的基本编号系统,1001 2 = 9 10 。如果在数字后没有使用下标,则通常假设成为小数。

    重复除2方法

    我们已经看到上面如何将二进制数转换为十进制数,但我们如何将十进制数转换为二进制数。将十进制数转换为二进制数等效的简单方法是写下十进制数并连续除以2(二)得到结果,并给出“1”或“0”的余数直到最终结果等于零。

    例如。将十进制数 294 10 转换为等效的二进制数。

    Number

    294

    如图所示,将每个十进制数除以“2”将得到一个结果加上一个余数。

    如果被分割的十进制数是偶数,那么结果将是整数并且余数将等于“0”。如果十进制数是奇数,那么结果将不会完全分割,余数将为“1”。

    二进制结果是通过将所有余数按最低有效位(LSB)排序得到的位于顶部,最重要位(MSB)位于底部。

    除以2

    结果

    147

    余数

    0(LSB)

    除以2

    结果

    73

    余数

    1

    除以2

    结果

    36

    余数

    1

    除以2

    结果

    18

    余数

    0

    除以2

    结果

    9

    余数

    0

    除以2

    结果

    4

    余数

    1

    除以2

    结果

    2

    余数

    0

    除以2

    结果

    1

    余数

    0

    除以2

    结果

    0

    余数

    1(MSB)

    这种除以2的十进制到二进制转换技术给出十进制数 294 10 相当于 100100110 2 二进制,从右到左阅读。这种2分频方法也适用于转换为其他数字基础。

    然后我们可以看到二进制编号系统的主要特征是每个“二进制数字” “或”位“具有”1“或”0“的值,每个位的权重或值是从最低位或最低位(LSB)开始的前一位的两倍,这称为”总和“权重“方法。

    因此我们可以通过使用权重和方法或使用重复的2分频方法将十进制数转换为二进制数,并将二进制数转换为十进制通过查找其权重和。

    二进制数字名称&amp;前缀

    二进制数可以加在一起,也可以像十进制数一样减去,结果根据所使用的位数组合成几个大小范围之一。二进制数有三种基本形式 - 位,字节和字,其中一位是单个二进制数字,一个字节是八位二进制数字,一个字是16位二进制数字。

    分类将各个位分成更大的组通常由以下更常见的名称引用:

    二进制数字位数(位) )

    通用名称

    1

    4

    半字节

    8

    字节

    16

    Word

    32

    双字

    64

    Quad Word

    此外,从 Binary转换为Decimal 或甚至从 Decimal转换为Binary ,我们需要注意不要混淆两组数字。例如,如果我们在页面上写入数字10,如果我们假设它是十进制数字,它可能意味着数字“十”,或者它可能同样是二进制中的“1”和“0”,这是等于上面加权十进制格式中的数字2。

    在将二进制数转换为十进制数并确定所使用的数字或数字是十进制数还是二进制数时,要克服此问题的一种方法是在最后一位数字后写一个称为“下标”的小数字,以显示该数字的基数正在使用的数字系统。

    因此,例如,如果我们使用二进制数字串,我们将添加下标“2”来表示基数为2,因此数字将写为 10 2 。同样,如果它是标准十进制数,我们将添加下标“10”来表示基数为10的数字,因此该数字将写为 10 10 。

    今天,随着微控制器或微处理器系统变得越来越大,现在将各个二进制数字(位)组合成8个,形成单个 BYTE 与大多数计算机硬件如硬驱动器和内存模块通常以兆字节或甚至千兆字节表示其大小。

    字节数

    通用名称

    1,024(2 10 )

    千字节(kb)

    1,048,576(2 20 )

    兆字节(Mb)

    1,073,741,824(2 30 )

    技嘉(Gb)

    a非常长的数字!(2 40 )

    太字节(Tb)

    二进制到十进制摘要

    A“ BIT “是源自 BI nary digi T

    十进制系统使用10个不同的数字,0到9给它一个10的基数

    二进制数是加权值从右到左增加的加权数

    二进制数字的权重从右到左翻倍

    十进制数可以通过使用权重和方法或重复的二分法来转换为二进制数

    当我们转换时数字从二进制到十进制,或十进制到二进制,下标用于避免错误

    将二进制转换为十进制(base-2到base-10)或十进制到二进制数(base10到base) -2)可以通过如上所示的多种不同方式完成。将十进制数转换为二进制数时,重要的是要记住哪个是最低有效位( LSB ),哪个是最高有效位( MSB )。

    在下一个关于二进制逻辑的教程中,我们将研究将二进制数转换为十六进制数,反之亦然,并显示二进制数可以用字母和数字表示。

    展开全文
  • 2、串口自定义协议接收一串十六进制数据进行存储,并将其中的两个字节转化为十进制数据 3、串口助手发送字符控制LED的亮灭 4、发送一个字节函数 5、发送两个字节函数 6、重定向printf和getchar函数

    一、基本储存单元

    • 位(bit):

      二进制数中的一个数位,可以是0或者1,是计算机中数据的最小单位。

    • 字节(Byte):

      计算机中数据的基本单位,每8位组成一个字节。各种信息在计算机中存储、处理至少需要一个字节。

      例如,一个ASCII码用一个字节表示,一个汉字用两个字节表示。

    • 字(Word):

      两个字节称为一个字。汉字的存储单位都是一个字。

    1个字节(byte)=8位(bit)数据
    1个汉字是一个字,即两个字节,16位数据

    二、通信协议

    通信方式-框图-参考链接

    (一)并行通信和串行通信

    • 并行通信

      8位数据并列的传输,传一个8位的数据是需要8根线一起传输。

      例如:SDIO,FSMC(16位的)–发送数据都是所有数据位同时传输
      在这里插入图片描述

    • 串行通信

      8位数据一位一位的传输,只需要一根线即可进行传输。

      例如:USART,IIC,SPI三种都是串行方式-----发送数据时都是一位一位的进行发送数据
      在这里插入图片描述

    • 串行通信与并行通信特征

    在这里插入图片描述

    (二)三种工作方式

    • 全双工

      有两根数据线,一个用来接收数据,一个用来发送数据,互不干扰,可以同时发送和接收数据。

      例如:usart(可以半双工或全双工通信),SPI(可以半双工或者全双工通信)

    • 半双工

      有两根数据线,但是不可以同时发送数据,可以分时收发数据

    • 单工

      只有一根数据线,只可以单向通信(只可以往某一个方向进行)

      例如:IIC

    000-串口通讯的单工、半双工和全双工的定义、区别及应用-

    (三)收发数据同步或异步传输

    • 同步通信

      数据同步方式,两个设备的时钟信号是同一个(有时钟信号的是同步)。

      在传输数据时为了保证数据传输的准确性:
      (1)时钟在高电平时,数据有效
      (2)时钟信号在低电平时数据时无效的
      (3)对时钟的要求很高(如果时钟有尖峰或者杂波,则数据传输就不准确了)

      例如:SPI,IIC通信接口。
      在这里插入图片描述

    • 异步通信

      没有时钟信号:为了保证数据传输的准确性是通过加上一些辅助的标识符

      例如:UART(通用异步收发器),单总线。
      在这里插入图片描述

    • 同步通信和异步通信比较

      (1)在同步通信中,数据信号所传输的内容绝大部分就是有效数据。
      (2)在异步通信中,传输的数据会包含有帧的各种标识符。
      (3)所以同步通信的效率更好,但是对于时钟允许误差较小,异步通信对于时钟允许误差较大。

    (四)通信速率

    • 比特率:每秒钟传输的二进制数单位:bit/s

      IIC,SPI(同步通信,一个时钟下传输一个数据,通过时钟来控制)

    • 波特率:每秒钟传输的码元个数(串口)

      一个二进制位表示一个码元(特殊情况下)

    三、串口通信协议

    物理层规定我们用嘴巴还是肢体进行交流
    协议层就是规定我们用汉语还是英文来交流

    (一)RS232

    1、RS232和TTL就是在电平上的区别

    TTL电平是直接从单片机(或者芯片)里面出来的:高电平用3.3V或者5v来表示,低电平用0表示
    RS232中1用-15V表示,0用+15V表示,逻辑正好时相反的,低电平和高电平的差距非常大
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    (二)USB转串口(TTL标准)

    在这里插入图片描述

    (三)串口到串口(TTL->TTL)

    在这里插入图片描述

    (四)串口数据包的基本组成

    在这里插入图片描述

    • 奇校验

    在这里插入图片描述

    • 偶校验

    在这里插入图片描述

    四、寄存器

    (一)状态寄存器:USART_SR

    在这里插入图片描述

    • TXE-发送数据寄存器空

      当TDR寄存器中的数据被硬件转移到移位寄存器的时候,TXE位被硬件置位。
      如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。

      0-数据还没有转移到移位寄存器
      1-数据已经转移到移位寄存器

    • TC-发送完成

      当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将TC位置’1’。
      如果USART_CR1中的TCIE=1,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。 TC位也可以通过写入’0’来清除,只有在多缓存通讯中才推荐这种清除程序。

      0-发送还没有完成
      1-发送已经完成

    • RXNE-读数据寄存器非空

      当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位(RXNE)被硬件置位。
      如果USART_CR1寄存器中的RXNEIE=1,则产生中断。对USART_DR的读操作可以将该位清零。 RXNE位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。

      0-数据没有收到
      1-收到数据可以读出

    (二)数据寄存器USART_DR

    在这里插入图片描述

    (三)控制寄存器1(USART_CR1)

    在这里插入图片描述

    • UE是使能串口 (1-模块使能)
    • TE是发送使能(0-禁止发送,1-使能发送)
    • RE是接收使能(0-禁止接收,1-使能接收)
    • PEIE是PE中断使能(0-禁止产生中断,1-当USART_SR的PE为1时,产生USART中断)
    • TCIE是发送完成中断使能(0-禁止产生中断,1-当USART_SR中的TC为’1’时,产生USART中断)
    • RXNEIE:接收缓冲区非空中断使能(0-禁止产生中断,1-当USART_SR中的ORE或者RXNE为’1’时,产生USART中断)

    (四)串口接收和发送数据

    • 发送数据流程

    在这里插入图片描述

    此时UE=1,TE=1
    上图对应的顺序依次是1->2->3,数据来源于CPU或者DMA,数据来了之后首先是放到发送寄存器(TDR)中,然后会再放到发送数据移位寄存器中,由于数据是8位的,会将数据一位一位的发送出去(使用TX引脚)。

    • 当数据由发送寄存器到发送数据移位寄存器时,TXE会被置1,即TXE=1,表示发送数据寄存器为空了,但是并不表示数据已经发送出去了。
    • 因为还要通过发送移位寄存器进行一位一位的发送数据,如果发送移位寄存器数据全部发送出去了,TC会被置1,即TC=1表示发送数据完毕。

    **

    • 接收数据流程

    **

    在这里插入图片描述
    此时UE=1,RX=1
    数据从RX引脚进来来,数据是一位一位进行接收的。

    • 首先放到数据接收移位寄存器
    • 然后将数据传递到数据接收寄存器(RDR),此时RXNE会被置1,即RXNE=1,表示数据接收寄存器不是空的(收到数据可以读出)

    五、STM32固件库函数

    在这里插入图片描述
    几个常用的固件库函数
    在这里插入图片描述
    在这里插入图片描述

    • 串口初始化函数

      void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);引脚、波特率、位数,校验、时钟等
      
    • 串口使能

       USART_Cmd(USART1, ENABLE); //使能串口—配置的是UE位
      
    • 中断使能

       void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT,FunctionalState NewState)
      
    • 发送数据

      STM32 库函数操作 USART_DR 寄存器发送数据的函数是:通过该函数向串口寄存器 USART_DR 写入一个数据。

      void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
      
    • 接收数据

      STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:通过该函数可以读取串口接收到的数据。

       uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
      
    • 获取标志位

      该函数只判断标志位。在没有使能相应的中断函数时,通常使用该函数来判断标志位是否置1

       Flagstatus USART_GetFlagStatus(USARTx,USART_FLAG)
      
    • 中断状态位获取函数

      不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断。所以在串口中断函数中,如果要获取中断标志位,通常使用该函数。

       ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t  USART_IT)
      
    • 清楚中断标志位

       Void  USART_Flag_Clear(USARTx,USART_FLAG)
      

    几个标志位函数的区分说明–链接

    六、USART应用

    串口初始化函数

    //初始化IO 串口1 
    //bound:波特率
    void uart_init(u32 bound){
        //GPIO端口设置
    		GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构体指针
    		USART_InitTypeDef USART_InitStructure;//串口结构体指针
    		NVIC_InitTypeDef NVIC_InitStructure;//中断分组结构体指针
    		//1、使能串口时钟,串口引脚时钟 
    		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
    		
    	//2、复位串口	
    		USART_DeInit(USART1);  //复位串口1
    	
    	//3、发送接收引脚的设置
    	 //USART1_TX   PA.9(由图 可知设置为推挽复用输出)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
       
        //USART1_RX	  PA.10(有图可知浮空输入)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10
    
    
       //4、USART 初始化设置
    
    		USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
    		USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    		USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    		USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    
        USART_Init(USART1, &USART_InitStructure); //初始化串口
    		
    #if EN_USART1_RX		  //如果使能了接收  
       //5、Usart1 NVIC 配置
    		NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
    		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    		NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
       
    	  //6、开启接收数据中断
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    		
    #endif
    		//7、使能串口
        USART_Cmd(USART1, ENABLE);                    //使能串口 
    
    }
    

    (一)发送数据

    1、函数1-串口发送一个字节数据

    void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data)
    {
    	//调用固件库函数
    	USART_SendData(pUSARTx,data);//往串口中写入数据
    	
    	//发送完数据是检测TXE这个位是否置1,发送数据寄存器空了,表明已经把数据传递到数据移位寄存器了
    	//检测TXE这个位也需要一个固件库函数
    	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);
    	//如果这个位一直为0的话就一直等待,只有当被设为SET后才会跳出这个循环(表示一个字节发送出去了)
    }
    

    在main主函数中编写语句:

    //在主函数里面发送一个数据试试
    Usart_SendByte(USART1,100);//往串口1中写入数据100
    

    串口调试助手并没有显示100,而是显示的一个字母d
    串口调试助手不管接收到的是什么数据,都会转化为字符
    只有发送十六进制数据,串口助手使用十六进制形式接收数据时才不是字符

    Usart_SendByte(USART1,'A');//往串口1里面写入一个字符A
    //串口接收到字符A
    

    串口助手无论是收发都是以字符的形式进行传输的

    假如说串口助手发送一个数字1,stm32串口如果能够接收的话,在进行数据解析过程中需要按照字符 ’1‘ 来进行解析(把1当成是字符,而不是十进制1 )

    2、函数2-发送两个字节数据

    有时候传感器数据可能是16位的,怎么发送?发送两个字节?

    发送两个字节的数据就是十六位的。

    //发送两个字节数据函数
    void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data)
    {
    	//发送十六位数据要分为两次来发送,先定义两个变量
    	uint8_t temp_h,temp_l;//定义8位的变量(分别存储高8位和低8位)
    
    	//首先取出高8位
    	temp_h=(data&0xff00)>>8;//低八位先与0相&,低8位变为0再右移8位(0xff00共16位二进制)
    	//再取出低8位
    	temp_l=data&0xff;//取出低8位数据
    	//16位的数据这样子就放到了两个变量里面(共16位)
    	
    	//调用固件库函数
    	USART_SendData(pUSARTx,temp_h);//先发送高8位
    	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);//等待数据发送完毕
    
    	USART_SendData(pUSARTx,temp_l);//再发送低8位
    	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);//等待数据发送完毕
    
    }
    

    在主函数中发送十六进制数据:

    Usart_SendHalfWord(USART1,0XFF56);//发送16位数据
    

    串口助手显示的是字符,要想接收到的数据和发送的一样,需要把串口助手选择为16进制接收
    串口助手接收到ff 56。虽然是16位的数据但是显示的时候还是一个字节一个字节的显示,十六进制ff是一个字节 56是一个字节
    在这里插入图片描述

    3、函数3-发送一个数组数据

    //发送一个数组数据
    void Usart_SendArray(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num)
    {
    	//每次想要发送多少数据,通过形参num传进来,num定义的是8位的,那么函数最多发送255个
    	int i;
    	for(i=0;i<num;i++)
    	{
    		//调用发送一个字节函数发送数据(下面两种写法都可以)
    		//Usart_SendByte(USART1,*array++);
    		Usart_SendByte(USART1,array[i]);//每次只能发送8位数据
    	}
    	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);//等待发送完毕
    }
    

    判断发送一个字节的数据标志位:USART_FLAG_TXE
    判断发送一连串字节的数据标志位:USART_FLAG_TC

    在主函数中定义一个数组

    uint8_t a[12]={1,2,3,4,5,6,7,8,9,10,98,100};
    

    将数据内容发送出去

    Usart_SendArray(USART1,a,12);
    

    串口助手:十六进制形式接收数据
    在这里插入图片描述

    串口助手:非十六进制数据形式接收数据:1-10的ASCII是无法显示的
    在这里插入图片描述

    4、函数4-发送字符串函数

    //发送字符串
    	void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str)//指定串口,要发送的字符串内容
    	{
    		uint8_t i=0;
    		//使用do-while循环,do的时候已经开始发送了
    		do{
    			//需要调用发送一个字节函数
    			Usart_SendByte(USART1,*(str+i));//发送一次之后指针地址后移一个
    			i++;
    		}while(*(str+i)!='\0');//最后结尾不等于'\0'为真,继续发送
    		//如果='\0'表示发送完毕
    		while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);//等待发送完毕
    	}
    

    在主函数中调用函数发送一个字符串

    Usart_SendStr(USART1,"欢迎使用stm32\n");//此时发送的是字符,串口助手要取消十六进制接收
    

    5、函数5-使用printf函数进行打印数据

    有时候想直接用printf函数直接发送,肯定是不可以的
    printf函数底层会有一个fputc,如果想要使用,需要重新定义

    int fputc(int ch FILE *f)
    {
    	//发送一个字节数据到串口
    	USART_SendData(USART1,(uint8_t)ch);
    	//等待发送完毕
    	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    	//检测发送数据寄存器是否为空USART_FLAG_TXE
    
    	return (ch);
    }
    

    在主函数中编写代码

    printf("串口测试实验\n");
    //发送一个字符也可以直接使用putchar('a')
    
    putchar('a');//串口助手会接收到字母a
    

    6、函数6-使用getchar函数

    getchar()等价于scanf()函数
    如果使用getchar函数也需要重新定义
    重定向c库函数scanf到串口,重写后可以使用scanf和getchar函数

    重定向c库函数scanf到串口,重写后可以使用scanf和getchar函数
    int fgetc(FILE *f)
    {
    	//等待串口输入数据
    	/* 有了这个等待就不需要在中断中进行了 */
    	while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
    	return (int)USART_ReceiveData(USART1);
    }
    

    如果在主函数中使用getchar()需要把下面的中断设置代码注释掉(下图),否则会冲突
    因为不需要在中断中进行

    在这里插入图片描述
    在主函数的while(1)循环中加入接收数据和发送数据的代码

    ch=getchar();
    printf("ch=%c\n",ch);//打印接收到的字符
    

    用串口助手发送什么字符,串口助手就会接收到单片机返回什么字符
    在这里插入图片描述

    (二)接收数据

    当接收到数据时产生中断

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    

    有中断就要设置中断优先级

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
    

    编写中断服务函数

    1、串口助手发送并返回数据中断函数

    串口助手发送什么数据给单片机,单片机自动将接收到的数据返回给串口助手

    //中断服务函数
    void USART1_IRQHandler() 
    {
    	u8 ucTemp;
    	if(USART_GetFlagStatus(USART1,USART_IT_RXNE)!=RESET)
    	{
    		ucTemp=USART_ReceiveData(USART1);
    		USART_SendData(USART1, ucTemp);
    	}
    }
    

    当外部设备或者串口调试助手给单片机发送数据时,单片机检测到数据接收寄存器非空,表示数据来了此时产生中断,进去中断服务函数调用固件库函数这个标志位是否真正置1,以免产生误中断,如果真的产生1时,调用USART_ReceiveData(USART1)函数接收数据,把数据放ucTemp变量中
    再调用USART_SendData(USART1, ucTemp)把数据发送回串口助手

    2、串口发送数据控制led亮灭

    通过串口接收到的数据进行控制led灯,这样子就不需要中断来接收了,通过查询方法即可,这时候要把中断部分给注释了,中断服务函数注释掉就可以了

    在主函数中加入以下代码:

       u8 ch;//存放电脑接收到的数据
    	while(1)
    	{
    		ch=getchar();//读取串口数据
    		printf("ch=%c\n",ch);//打印接收到的字符
    		switch(ch)//进行匹配
    		{
    			case '1':
    				LED0=0;break;//打开LED0
    			case '2':
    				LED1=0;break;//打开LED1
    		}
    
    	}
    

    如果出现错误:参考此链接
    解决方案-链接
    使用串口助手分别发送1和2就可以控制led灯的亮灭了
    在这里插入图片描述

    3、STM32自定义协议接收十六进制数据(使用三合一气体传感器求出CO2浓度)

    前面已经说到,如果不勾选十六进制数据接收和发送的话,其他情况都是以字符的形式发送和接收的,所以此处在发送和接收数据时都要将hex选项进行勾选

    三合一气体传感器串口数据流格式如下:
    在这里插入图片描述

    由于前两个字节数据是固定的模块地址,因为可以用来当做判断标准,定义一个接收数据的协议:只有第一个字节和第二个字节都符合条件时,才将数据存储到数组中

    模块数据流:2C E4 04 00 00 AD 03 38 FC

    数据流共9个字节,所以先定义一个存储9个字节的八位数组

    u8 table_data[9];//这是提前定义一个数组存放接收到的数据
    u8 table_cp[9];//这是额外定义一个数组,将接收到的数据复制到这里面
    u16 count=0;//接收数据计数
    

    编写中断服务函数

    //使用自定义协议接收十六进制数据
    
    void USART1_IRQHandler(void)                	//串口1中断服务程序
    {
    		u8 Res,i;
    		if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
    		{
    			Res =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
    			
    			if(count==0)//如果是接收的第一个数据
    			{
    				table_data[count]=Res;//将第一个数据存到数据中第一元素
    				if(table_data[0]==0x2c)//判断接收的第一个数据是不是十六进制0X2C
    				  count++;//如果第一个数据是0X2C则表示正确计数+1
    			}
    			else if(count==1)//第一个数据接收正确的情况下,判断第二个数据
    			{
    				if(Res==0xe4)//如果刚接收的数据是0xE4则表示数据正确
    				{
    					table_data[count]=Res;//将数据储存到数组第二个元素位置
    					count++;//接收数据计数+1
    				}
    				else//如果第二个字符不是0XE4则计数清零,重新接收
    					count=0;
    			}
    			else if(count==2&&Res==0)//如果前两个数据正确,接收的第三个数据是0,则清零计数,重新接收数据
    			{
    				count=0;
    			}
    			else if(count>1&&count<9)//这是可以接收数据的范围,只要count在数据可接收数据范围内即可进行存入数据
    			{
    				table_data[count]=Res;
    				count++;
    			}
    			else if(count>=9)//如果接收数据超过数组大小,则清零重新接收
    			{
    				count=0;
    			}		
       } 
    	 
    		memset(table_cp, 0, sizeof(table_data));//在使用数组table_cp时清空
    		for(i=0;i<9;i++)//把接收到的数据复制到table_cp数组中
    		{
    			 table_cp[i]= table_data[i];
    	}
    } 
    

    上面实现的是通过自定义协议接收并存储数据

    在接收到十六进制数据之后,想要提取其中的两个字节并将其转化为十进制数据,首先需要编写一个十六进制转换函数:(输入十六进制数据返回十进制数据

    int hextoDec(int hex)
    {
    	 int sum=0,mul=1;
    	 int i,r;
    	 int count=0;
    	 do{
    	  r=hex%16;
    	  for(i=0;i<count;i++)
    	   mul*=16;
    	  mul*=r;
    	  sum+=mul;
    	  mul=1;
    	  count++; 
    	 }while(hex/=16);
    	 return sum;
    }
    

    主函数的while内容如下:

    while(1)
    	{
    	  if(table_cp[0]==0x2c)//如果数组第一个十六进制数据是0X2C则进行
    		{
    			//用十进制数据打印一下接收到的数据
    			//原始数据(十六进制数据)是2C E4 04 00 00 AD 01 23 FC
    			//前两位是固定的,第7个和第8个十六进制数据分别是CO2的高八位和低八位
    			for(i=0;i<9;i++)
    			{
    					printf(" %d \n",table_cp[i]);
    				
    			}
    			
    			printf("\r\n");//加一个回车换行
    			//把对应的十六进制数据转化为十进制数据
    			num_H=hextoDec(table_cp[6]);//高8位
    			num_L=hextoDec(table_cp[7]);//低8位
    			printf("hh=%d LL=%d \n",num_H,num_L);
    			num=num_H*256+num_L;//使用CO2浓度计算公式计算出数值
    			printf("CO2=%d\n",num);
    				
    			}
    	}
    

    在这里插入图片描述
    验证如下:
    如下图所示:使用串口助手发送十六进制数据:
    2C E4 04 00 00 AD 03 38 FC

    其中第7个字节是CO2的高8位,第8个字节是CO2浓度的低8位,然后再按照计算公式进行计算即可求出二氧化碳浓度
    在这里插入图片描述

    完整代码下载链接

    展开全文
  • c#字节数组转十进制

    千次阅读 2019-12-09 23:17:23
    public static decimal ByteArrayToDecimal(byte[] src) { // Create a MemoryStream containing the byte array ...
  • import java.nio.charset.Charset; import org.apache.commons.lang3.ArrayUtils;... * @Description: 字节数组转换工具类 * @author fun * @date 2019年3月27日 */ public class BytesUtil...
  • 由于项目需要,需要将十进制数据转为十六进制,并且,用两个字节表示。 代码如下: int i=100; byte[] pack=new byte[2] byte[] byte_i=BitConverter.GetBytes(baseId);//此函数将十进制转为四个字节的十六进制 ...
  • 两个16进制字节转换十进制,帮我看一下这个程序有问题吗,多谢多谢![图片](https://img-ask.csdn.net/upload/201706/26/1498445605_257523.jpg)
  • C语言 · 十六进制转十进制问题描述从键盘输入一不超过8位的正的十六进制数字符串,将它转换为正的十进制数后输出。注:十六进制数中的10~15分别用大写的英文字母A、B、C、D、E、F表示。样例输入FFFF样例输出65535...
  • 实验内容:输入一个十进制数把它转换为二进制数并且输出在控制台中 实验要点:(1)利用乘法(2)从高位开始处理 实验思路:(1)通过调用10号功能调用,将键入的十进制数存入定义的缓冲区IBUF中 (2)缓冲区...
  • 将二进制转换十进制 C语言

    千次阅读 2021-08-31 20:55:13
    函数fun的功能是将一由字符0和1组成的表示二进制数的字符串,转换成相应的十进制整数值返回。该串长度最大不超过15。 例如,若表示二进制数的字符串:"10011",则运行结果应:10011-->19 #include <...
  • 中断收到两个16进制字节rec0(低位)和rec1(高位),如何将其转换成10进制,求这一段完整代码
  • 我知道您可以使用printf并...但我希望能够实际格式化字节数组,以便每个字节显示HEX而不是十进制.这是我的代码的一部分,我已经说过我说的前种方式:if(bytes > 0){byteArray = new byte[bytes]; // Set up a...
  • 本文向您展示了几种转换字节数组或byte[]转换为十六进制(基数 16 或十六进制)字符串代表的方法。 String.format Integer.toHexString Apache Commons 编解码器 –commons-codec Spring 安全加密 –spring-...
  • 常用的进制有二进制,八进制,十进制,十六进制。 二.将整数转换成十六进制 二.一 将int整数转换成十六进制(一) 先写一主方法,接下来,所有的方法都是通过main 方法来调用的。 不用Junit测试。 做静态的方法,...
  • 1二进制数1101.1111转换成十六进数应()A.A.FB.E.FC.D.FD.A.E2二进制数110101对应的十进制数是()A.44B.65C.53D.743二进制数11011+1101等于()A.100101B.10101C.101000D.100114二进制数11101011-10000100等于()A....
  • 进制数据是用0和1两个数码来表示的数。但是很多人都会将二进制转换成整数,但是如何用二进制表示负数呢?有的人会说,在二进制前面加个负数符合。而计算机只能认识0 和 1,又怎么去加个额外的负数符号呢?于是我们...
  • 十进制转换为二进制数的方法:从十进制数的最高位Dn开始作乘10加次位的操作,将结果乘以10再加下一次位数,如此重复便可求出二进制数的结果。 汇编语言实现ASCII码表示的十进制转换为二进制 ;功能描述:将...
  • 这是将字节数组byte[]转换为Hexadecimal的两个Java示例。 Apache Commons编解码器 整数 可能重复 请参阅此以获取更多代码段– 用Java将字符串转换为十六进制 1. Apache Commons编解码器 最简单的方法。 ...
  • 字节等单位与进制转换

    千次阅读 2019-03-03 18:10:28
    字符与字节 ASCII码:一个英文字母(不分大小写)占一个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般8位二进制数。...Unicode编码:一个英文等于两个字节,一个中文(含繁体)等...
  • & 十六进制数(String型)) 十进制转换为十六进制:十六进制数(String型)=Hex$(十进制) 例如十进制数57,在二进制写作111001,在16进制写作39。在历史上,中国曾经在重量单位上使用过16进制,比如,规定16两为一斤...
  • --------------------------------------------- -- 时间:2019-01-11 -- 创建人:Ruo_Xiao ...-------------------------------------... 这天在处理TCP发送数据的问题,对方发来4个字节的浮点数的16进制,当时脑袋...
  • 将8421BCD码转换为十进制数(转)

    千次阅读 2021-05-22 14:28:49
    //*****************************************************************//bcd hex//此函数用于将8421BCD码转换为十进制数,从函数参数可以看出此BCD码是由十进制数组成的。BCD码是用二进制数对十进制数的各...
  • 直接使用这方法,就能将数据转化对应的十进制数, 但是这一般只能适用正数 2.负数二进制、十六进制转化为十进制 一把二进制数八位表示,bit8位代表符号 0正 1负 ; 十六进制也是可以使用八位表示例如FFFFFFFF...
  • 1个字节:最大0xFF = 255(存储类型byte和char) 2个字节:最大0xFF FF = 65535(存储类型shot int) 4个字节:最大0xFF FF FF FF= 4294967295(存储类型int 、long) 8个字节:最大0xFF FF FF FF FF FF FF FF= ...
  • 十进制转十六进制

    2021-12-14 18:12:33
    分析:从控制台输入一个十进制整数,将其转换成十六进制数输出,接着提取其4个字节。用到按位与运算符“&”、右移位运算符“>>”。 ps:“0x”是十六进制数的前缀。位(bit):度量数据的最小单位,表示...
  • 在C语言某个程序当中需要把文本16进制转换成对应的16进制数,比如字符串"0x1a"转换成10进制的26,可以用以下函数来实现相关函数: atof, atoi, atol, strtod, strtoul表头文件: #include 定义函数: long int strtol...
  • 数组(九)--十进制转换为十六进制

    千次阅读 2017-10-31 21:00:35
    方法一: 1、以60例:(假设32位) 60 除以 16 商 3 余。...2、然后将余数倒过来,位数的余数则转化字母。 数字与字母对应: 10-----A 11-----B 12-----C 13-----D 14-----E 15----

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 128,392
精华内容 51,356
关键字:

两个字节转换为十进制

友情链接: Loader.rar