单片机c语言16进制转10进制

99ANYc3cd6
预计阅读时长 24 分钟
位置: 首页 C语言 正文
  1. 将一个16进制常量显示为10进制字符串(通过串口打印到屏幕上),这是最常见的需求。
  2. 将一个表示16进制数的字符串转换为一个真正的10进制整数(从串口接收到 "1A",然后将其转换为数值 26)。

下面我将详细解释这两种场景的实现方法,并提供完整的示例代码。

单片机c语言16进制转10进制
(图片来源网络,侵删)

将16进制常量显示为10进制字符串

这是最简单的情况,假设你有一个16进制数,你想把它当作一个10进制数来显示,在C语言中,这非常直接。

方法:使用 printfsprintf

标准C库中的 printf 函数是完成这个任务的最佳工具,你只需要使用 %d%u 格式说明符即可。

  • %d:用于有符号十进制整数 (int)。
  • %u:用于无符号十进制整数 (unsigned int)。

示例代码 (基于Keil C51)

假设你有一个16进制数 0x1A,它的10进制值是26。

#include <stdio.h> // 必须包含 stdio.h 才能使用 printf
void main(void)
{
    // 定义一个16进制变量
    unsigned char hex_value = 0x1A; // 0x1A 等于 26
    // 方法1:直接使用 printf 打印
    // %u 表示以无符号十进制形式输出
    printf("直接打印: hex_value = %u\n", hex_value);
    // 方法2:使用 sprintf 将结果存入字符串
    // 这在单片机中非常有用,比如要通过串口发送数据
    char output_string[20]; // 定义一个足够大的字符数组来存放结果
    sprintf(output_string, "通过sprintf: hex_value = %u", hex_value);
    // 在实际应用中,你可能需要将 output_string 通过串口发送出去
    //  UART_Send_String(output_string);
    while(1)
    {
        // 主循环
    }
}

代码解析

  1. #include <stdio.h>:包含了标准输入输出函数库,printfsprintf 都在其中。
  2. unsigned char hex_value = 0x1A;:我们定义了一个变量 hex_value 并用16进制 0x1A 为其赋值,在C语言中,0x 前缀表示这是一个16进制数,编译器在处理这个赋值时,会自动将 0x1A 转换为其内部的二进制表示(即十进制的26)。
  3. printf("...", hex_value);printf 函数会读取 hex_value实际数值(26),然后根据 %u 格式说明符,将其格式化为 "26" 这个字符串并打印出来。
  4. sprintf(output_string, "...", hex_value);:这个函数和 printf 类似,但它不是打印到屏幕,而是将格式化后的字符串写入到第一个参数指向的字符数组中,这在嵌入式系统中非常常见,因为单片机通常没有屏幕,但可以通过串口将字符串发送到电脑上显示。

适用于单片机的 printf 重定向

在标准的单片机开发环境中(如Keil C51),printf 默认可能不会输出到串口,你需要自己实现一个底层输出函数(通常是 fputc),并将其重定向到你的串口发送函数。

单片机c语言16进制转10进制
(图片来源网络,侵删)

示例:重定向 printf 到串口

#include <stdio.h>
// 假设这是你的串口发送一个字符的函数
void UART_SendChar(char ch)
{
    // 这里实现你的UART发送单个字节的代码
    // SBUF = ch;
    // while(!TI); TI = 0;
}
// 重定向 fputc 函数到串口
int fputc(int ch, FILE *f)
{
    UART_SendChar(ch);
    return ch;
}
// 现在你可以直接使用 printf 了,它会自动调用 UART_SendChar
void main(void)
{
    unsigned int hex_num = 0xFF; // 16进制FF,等于10进制255
    printf("The decimal value of 0xFF is: %d\n", hex_num);
    while(1);
}

将16进制字符串转换为10进制整数

这种情况更复杂一些,你得到的不是一个数值,而是一个字符数组(字符串),"1A"、"FF"、"42" 等,你需要将它转换成一个真正的整数(将 "1A" 转换为 26)。

方法:手动编写转换函数

最可靠和通用的方法是手动编写一个转换函数,因为标准C库的 strtol 函数在某些单片机编译器中可能不被支持或需要额外配置。

示例代码 (手动转换函数)

这个函数可以处理大写和小写的16进制字符。

单片机c语言16进制转10进制
(图片来源网络,侵删)
#include <stdio.h>
/**
 * @brief  将16进制字符串转换为无符号整数
 * @param  hex_str: 指向16进制字符串的指针 ("1A", "FF", "0x1A")
 * @param  result: 用于存储转换结果的指针
 * @return 0: 成功, -1: 失败 (例如字符串包含非法字符)
 */
int HexStringToUInt(const char *hex_str, unsigned int *result)
{
    unsigned int temp = 0;
    char c;
    if (hex_str == NULL || result == NULL) {
        return -1;
    }
    // 检查是否有 "0x" 或 "0X" 前缀,如果有则跳过
    if (hex_str[0] == '0' && (hex_str[1] == 'x' || hex_str[1] == 'X')) {
        hex_str += 2;
    }
    // 遍历字符串的每个字符,直到遇到字符串结束符 '\0'
    while ((c = *hex_str++) != '\0') {
        // 将字符转换为大写,简化判断
        if (c >= 'a' && c <= 'f') {
            c -= 32; // 'a' -> 'A', 'b' -> 'B', ...
        }
        // 判断字符是否为有效的16进制数字
        if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
            // 将字符转换为对应的数值
            if (c >= '0' && c <= '9') {
                temp = temp * 16 + (c - '0');
            } else { // 'A' to 'F'
                temp = temp * 16 + (c - 'A' + 10);
            }
        } else {
            // 遇到非法字符,转换失败
            return -1;
        }
    }
    *result = temp;
    return 0;
}
// --- 主函数示例 ---
void main(void)
{
    unsigned int decimal_value;
    const char *hex_str1 = "1A";
    const char *hex_str2 = "FF";
    const char *hex_str3 = "0x42"; // 带前缀的
    const char *hex_str4 = "G12";  // 非法字符串
    // 转换 "1A"
    if (HexStringToUInt(hex_str1, &decimal_value) == 0) {
        // printf("'%s' in decimal is: %u\n", hex_str1, decimal_value);
        // 假设你有一个串口打印函数
        UART_SendString("'");
        UART_SendString(hex_str1);
        UART_SendString("' in decimal is: ");
        UART_SendNumber(decimal_value); // 需要自己实现UART_SendNumber
        UART_SendString("\n");
    }
    // 转换 "FF"
    if (HexStringToUInt(hex_str2, &decimal_value) == 0) {
        // printf("'%s' in decimal is: %u\n", hex_str2, decimal_value);
        UART_SendString("'");
        UART_SendString(hex_str2);
        UART_SendString("' in decimal is: ");
        UART_SendNumber(decimal_value);
        UART_SendString("\n");
    }
    // 转换 "0x42"
    if (HexStringToUInt(hex_str3, &decimal_value) == 0) {
        // printf("'%s' in decimal is: %u\n", hex_str3, decimal_value);
        UART_SendString("'");
        UART_SendString(hex_str3);
        UART_SendString("' in decimal is: ");
        UART_SendNumber(decimal_value);
        UART_SendString("\n");
    }
    // 尝试转换非法字符串 "G12"
    if (HexStringToUInt(hex_str4, &decimal_value) != 0) {
        // printf("Error: '%s' is not a valid hex string.\n", hex_str4);
        UART_SendString("Error: '");
        UART_SendString(hex_str4);
        UART_SendString("' is not a valid hex string.\n");
    }
    while(1);
}

代码解析

  1. 函数 HexStringToUInt:

    • 输入: 一个字符串指针 hex_str 和一个用于存储结果的整数指针 result
    • 处理:
      • 首先检查输入是否有效。
      • 使用 while 循环逐个处理字符串中的字符。
      • *`temp = temp 16 + ...**: 这是核心算法,它将当前累积的结果temp` 左移4位(相当于乘以16),然后加上当前字符对应的数值。
      • 字符转换: 通过判断字符的ASCII码范围,将其转换为0-9或10-15的数值,字符 '5' 的ASCII码是53,'5' - '0' (53 - 48) 结果就是5,字符 'A' 的ASCII码是65,'A' - 'A' + 10 (65 - 65 + 10) 结果就是10。
      • 错误处理: 如果遇到任何不是0-9, A-F, a-f的字符,函数立即返回-1表示失败。
    • 输出: 通过指针 result 将转换后的整数返回给调用者,并返回0表示成功。
  2. 主函数:

    • 演示了如何调用 HexStringToUInt 函数。
    • 处理了多种情况:普通16进制字符串、带 0x 前缀的字符串以及非法字符串。
    • 注释中提到的 UART_SendNumber 是一个需要你自己实现的函数,它接收一个整数,然后像场景一中的 sprintf 那样,将其转换为字符串并发送出去。

场景 目标 方法 关键函数/技术
场景一 16进制常量 显示为 10进制字符串 直接使用格式化输出 printf, sprintf
场景二 16进制字符串 转换为 10进制整数 手动编写解析函数 自定义转换函数,处理ASCII码

对于大多数单片机应用,场景一 最为常见,掌握 printf 的使用和重定向是基本技能,而 场景二 在处理外部输入(如串口指令、配置文件等)时非常有用,理解其背后的算法原理非常重要。

-- 展开阅读全文 --
头像
在c语言中 合法的长整型常数是
« 上一篇 01-07
dede 调用upload原图
下一篇 » 01-07

相关文章

取消
微信二维码
支付宝二维码

目录[+]