自己动手写C语言float浮点数转换字符串的函数

news2024/11/15 23:26:24

最近在项目中用到了holtek厂商的HT45F24A和BA45F5650两款单片机。
用的开发工具是HT-IDE3000,烧录软件是HOPE3000。
这两款单片机都是8位的单片机,支持寄存器位操作。
HT45F24A单片机不带UART串口,要想实现串口功能,只能自己用定时器操作GPIO来模拟UART发送时序。
BA45F5650单片机带UART串口,可直接使用。
IDE里面支持float和double浮点类型,但是却没有<stdio.h>头文件,不支持printf函数,sprintf函数,编译器不支持stdarg可变参数函数,所以也没法自己实现printf函数。
IDE里面有字符串转浮点数的函数,却没有浮点数转字符串的函数,这个功能得自己编程实现。
另外,IDE里面的float是3/4精度浮点数(3字节),double是单精度浮点数(4字节)。
而电脑上的float是单精度浮点数(4字节),double是双精度浮点数(8字节)。

程序下载链接:https://pan.baidu.com/s/1SLjIJdzTKRk06zur2QshhQ?pwd=m8ay

先在电脑上用Visual Studio 2010实现4字节单精度浮点数转字符串的功能。
双精度浮点数double和四精度浮点数long double转字符串已经有人写出来了:
https://www.cnblogs.com/carekee/articles/3124256.html
只需要参照他的思想,写一个单精度浮点数float的转换函数就可以了。

【ftoa.h】

#pragma once

#define FTOA_PRECISION 8 // 转换时保留的有效数字位数
#define FTOA_PRECISION_MAX 1e8 // 必须等于10^FTOA_PRECISION
typedef uint32_t ftoa_fixnum_t; // 此类型至少要能保存10*FTOA_PRECISION_MAX那么大的数

#define FLOAT_VAL(var) (*(float *)&(var))
#define FLOAT_HEXVAL(var) (*((uint32_t *)&(var)))
#define FLOAT_SIGN(var) (FLOAT_HEXVAL(var) >> 31) // 1bit
#define FLOAT_CLEARSIGN(var) (FLOAT_HEXVAL(var) & 0x7fffffff)
#define FLOAT_EXPONENT(var) (((FLOAT_HEXVAL(var) >> 23) & 0xff) - 127) // 8bits
#define FLOAT_MANTISSA(var) (FLOAT_HEXVAL(var) & 0x7fffff) // 23bits
#define MAKE_FLOAT_HEXVAL(s, e, m) ((((uint32_t)(s) & 1) << 31) | (((uint32_t)((e) + 127) & 0xff) << 23) | ((uint32_t)(m) & 0x7fffff))
#define MAKE_FLOAT(f, s, e, m) FLOAT_HEXVAL(f) = MAKE_FLOAT_HEXVAL((s), (e), (m))

char *ftoa(float value);
char *ltoa(long value);

【ftoa.c】

#include <stdint.h>
#include <string.h>
#include "ftoa.h"

static const float float_table[31] = {
	1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, 1.0e6f, 1.0e7f, 1.0e8f, 
	1.0e9f, 1.0e10f, 1.0e11f, 1.0e12f, 1.0e13f, 1.0e14f, 1.0e15f, 1.0e16f, 
	1.0e17f, 1.0e18f, 1.0e19f, 1.0e20f, 1.0e21f, 1.0e22f, 1.0e23f, 1.0e24f, 
	1.0e25f, 1.0e26f, 1.0e27f, 1.0e28f, 1.0e29f, 1.0e30f, 1.0e31f
};
static const float float_table_2[1] = {1.0e32f};

char *ftoa(float value)
{
	static char str[50];
	char *p = str;
	float num;
	ftoa_fixnum_t fixnum;
	int16_t e, k, a, b, i;
	uint8_t negative = FLOAT_SIGN(value);

	/* 总体思想 */
	// (1) 如果浮点数的整数部分能够放进一个整型变量里面, 直接把这个整型变量的值转换成十进制字符串就行了
	// (2) 如果浮点数的整数部分太大, 超过了整型变量的取值范围, 则除以10^k, 就能成功放进整型变量里面了, 然后把整型变量转换成十进制字符串, 字符串末尾要添0
	// (3) 如果浮点数的整数部分为0, 只有小数部分, 那么乘以10^(-k), 整数部分就不是0了, 放进整型变量后就可以转换成字符串了, 再在合适的位置点上小数点
	// 为了使结果包含尽可能多的有效数字, 应该正确选择k值, 使整数部分能够尽可能占满整型变量的最大存储空间
	// 变量e决定了最后在字符串的什么位置点上小数点

	/* 第一步: 先把|value|改写成num*(10^k)的形式 */
	// |value|=num*(10^k), 其中k=32*a+b
	// num的整数部分的大小有如下两个要求:
	// (1) 必须要在ftoa_fixnum_t类型能表示的数值范围内, 并且不能为负数
	// (2) 数位尽可能多, 最好是有FTOA_PRECISION位数

	// 将二进制指数转化成十进制指数
	// 设2^x=10^e, 则e=lg(2^x)=xlg2 (x就是浮点数里面那个二进制指数)
	// lg2是一个无理数, 可以取近似值19728/65536
	e = FLOAT_EXPONENT(value);
	if (e == -127)
	{
		if (!negative)
			strcpy(str, "0");
		else
			strcpy(str, "-0");
		return str;
	}
	else if (e == 128)
	{
		if (FLOAT_MANTISSA(value) == 0)
		{
			if (!negative)
				strcpy(str, "inf");
			else
				strcpy(str, "-inf");
		}
		else
		{
			if (!negative)
				strcpy(str, "nan");
			else
				strcpy(str, "-nan");
		}
		return str;
	}
	e = ((int32_t)e * 19728) / 65536; // 由于lg2的值不精确, 所以这里的e值是近似值, 但是没有关系, 只要整型变量fixnum能放得下num, 就不会转换出错
	// 根据e的值确定k值, 使num的数位尽可能多
	k = -(FTOA_PRECISION - (e + 1)); // e是科学计数法的指数, 那e+1就是位数, 例如10^4是5位数
	// 再根据k值和value值确定num值
	// k/32=a......b
	// num=|value|/(10^k)
	//    =|value|/[10^(32*a+b)]
	//    =|value|/[10^(32*a)]/(10^b)
	FLOAT_HEXVAL(num) = FLOAT_CLEARSIGN(value); // 取浮点数绝对值
	if (k > 0)
	{
		a = k / 32;
		b = k % 32;
		if (a != 0)
			num /= float_table_2[a - 1];
		if (b != 0)
			num /= float_table[b - 1];
	}
	else if (k < 0)
	{
		a = (-k) / 32;
		b = (-k) % 32;
		if (a != 0)
			num *= float_table_2[a - 1];
		if (b != 0)
			num *= float_table[b - 1];
	}
	// num的整数部分四舍五入
	// 0.4+0.5=0.9=>0, 0.5+0.5=1.0=>1, 0.6+0.5=1.1=>1
	num += 0.5f;

	// 如果num的位数<FTOA_PRECISION, 可以在前面补0, 补够FTOA_PRECISION位数
	// 但如果发现num>=FTOA_PRECISION_MAX, 那么num的位数就不是<=FTOA_PRECISION, 而是=FTOA_PRECISION+1
	// 位数多了一位, 说明前面的e值太小了, 导致k的大小不合适
	if (num >= FTOA_PRECISION_MAX)
	{
		// e的值增加1, 然后k的值也增加1
		e++;
		k++;
		// 为了使等式|value|=num*(10^k)仍然成立, num的值要缩小10倍才行
		num /= 10;
	}
	// num是由|value|/(10^k)得来的, 理论上无论k取几, num的值都是value的十进制小数位
	// 比如num=12345678901234567890, 当k=15时, num=12345; 当k=12时, num=12345678
	// 就算是前面e的值因lg2不精确没算准确, 也不可能出现num不是value的十进制小数位的情况, 搞清楚这一点非常重要
	// k的值又是由e的值得来的, 所以小数点是不可能点错位置的
	// 只不过k的大小如果不合适, 那么num的大小就会太大或者太小, 没法存到fixnum整型变量里面, 就没法转成字符串

	/* 第二步: 取num的整数部分, 存到fixnum整型变量中, 舍弃小数部分 */
#if 0
	// (方法1)
	fixnum = (ftoa_fixnum_t)num;
#else
	// (方法2)
	// 请注意在浮点数标准格式里面, 尾数是有小数点的, 小数点在尾数的最左侧, 小数点左边还有一个隐藏的1
	fixnum = FLOAT_MANTISSA(num) | (1ul << 23); // 取尾数, 补上小数点前隐藏的1, 然后去掉小数点
	i = FLOAT_EXPONENT(num) - 23; // 取指数 (因为上一步去掉了小数点, 导致原数扩大了2^23倍, 所以取出来的指数要减23)
	// 乘上2的(指数-23)次方
	if (i > 0)
		fixnum <<= i; 
	else if (i < 0)
		fixnum >>= -i;
#endif

	/* 第三步: 根据e值和fixnum值输出字符串 */
	// 小数点的位置应该点在fixnum数值从左边数第e+1位数的后面
	if (negative)
		*p++ = '-';
	if (e + 1 < 1)
	{
		// 如果e + 1 < 1, 就要在前面添0
		*p++ = '0';
		*p++ = '.';
		while (e + 1 < 0)
		{
			*p++ = '0';
			e++;
		}
		// 后面只有数字, 不再添加小数点
		i = FTOA_PRECISION;
	}
	else if (e + 1 < FTOA_PRECISION)
	{
		// 小数点在数字中间
		i = FTOA_PRECISION + 1;
	}
	else
	{
		// 没有小数点, 数字末尾可能要补0
		i = e + 1;
	}
	p[i--] = '\0';
	while (i >= 0)
	{
		if (i >= FTOA_PRECISION && e + 1 >= FTOA_PRECISION)
			p[i--] = '0';
		else
		{
			if (i == e + 1 && i != 0)
				p[i--] = '.';
			p[i--] = '0' + fixnum % 10;
			fixnum /= 10;
		}
	}

	/* 第四步: 去掉小数点末尾多余的0 */
	if (e + 1 < FTOA_PRECISION)
	{
		i = FTOA_PRECISION;
		if (p[i] == '\0')
			i--;
		while (i >= 0 && p[i] == '0')
		{
			p[i] = '\0';
			i--;
		}
		if (i >= 0 && p[i] == '.')
			p[i] = '\0';
	}
	return str;
}

char *ltoa(long value)
{
	static char str[12];
	char temp;
	uint8_t i, n, start = 0;
	
	if (value == 0)
	{
		str[0] = '0';
		str[1] = '\0';
	}
	else
	{
		// 正数的最大值是2147483647
		// 负数的绝对值的最大值是2147483648
		// 负数的表示范围更大, 所以把所有的正数都转换成负数
		if (value < 0)
		{
			str[0] = '-';
			start = 1;
		}
		else
			value = -value;
		
		// 从左到右依次存放低位到高位
		for (i = start; value != 0; i++)
		{
			str[i] = '0' + (-(value % 10));
			value /= 10;
		}
		str[i] = '\0';
		
		// 字符串倒序: 高位移到左边, 低位移到右边
		n = i - start;
		for (i = 0; i < n / 2; i++)
		{
			temp = str[start + i];
			str[start + i] = str[start + n - i - 1];
			str[start + n - i - 1] = temp;
		}
	}
	return str;
}

【main.c】

#include <stdint.h>
#include <stdio.h>
#include "ftoa.h"

int main(void)
{
	float f;

	MAKE_FLOAT(f, 0, 13, 7 << 20);
	printf("1.875*(2^13)=%s\n", ftoa(f));
	printf("%s\n", ftoa(-0.00075f));
	printf("%s\n", ftoa(-3.1415926f));
	printf("%s\n", ftoa(-13.1415926f));
	printf("%s\n", ftoa(0.0012345678f));
	printf("%s\n", ftoa(0.012345678f));
	printf("%s\n", ftoa(0.12345678f));
	printf("%s\n", ftoa(1.2345678f));
	printf("%s\n", ftoa(12.345678f));
	printf("%s\n", ftoa(123.45678f));
	printf("%s\n", ftoa(1234.5678f));
	printf("%s\n", ftoa(12345.678f));
	printf("%s\n", ftoa(123456.78f));
	printf("%s\n", ftoa(1234567.8f));
	printf("%s\n", ftoa(12345678.0f));
	printf("%s\n", ftoa(123456789.0f));
	printf("%s\n", ftoa(123456789012.0f));
	printf("%s\n", ftoa(1.23e38f));
	printf("%s\n", ftoa(-1.23e-38f));
	
	MAKE_FLOAT(f, 0, -127, 0);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 0, -127, 7 << 20);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 1, -127, 0);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 1, -127, 7 << 20);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 0, 128, 0);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 0, 128, 7 << 20);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 1, 128, 0);
	printf("%f %s\n", f, ftoa(f));
	MAKE_FLOAT(f, 1, 128, 7 << 20);
	printf("%f %s\n", f, ftoa(f));

	printf("%s ", ltoa(0));
	printf("%s ", ltoa(123450));
	printf("%s\n", ltoa(-67890));
	printf("%s ", ltoa(2147483647));
	printf("%s ", ltoa(-2147483647));
	printf("%s\n", ltoa(-2147483647 - 1));

	return 0;
}

程序运行结果:

然后再移植到BA45F5650单片机上运行。
【strconv.h】

#define FTOA_PRECISION 8
#define FTOA_PRECISION_MAX 1e8
typedef uint32_t ftoa_fixnum_t;

#define FLOAT_SIGN_HEXVAL(hexval) (((hexval) >> 23) & 1) // 1bit
#define FLOAT_CLEARSIGN_HEXVAL(hexval) ((hexval) & 0x7fffff)
#define FLOAT_EXPONENT_HEXVAL(hexval) ((((hexval) >> 15) & 0xff) - 127) // 8bits
#define FLOAT_MANTISSA_HEXVAL(hexval) ((hexval) & 0x7fff) // 15bits
#define MAKE_FLOAT_HEXVAL(s, e, m) ((((uint32_t)(s) & 1) << 23) | (((uint32_t)((e) + 127) & 0xff) << 15) | ((uint32_t)(m) & 0x7fff))
#define MAKE_FLOAT(f, s, e, m) \
		do { \
			uint32_t temp = MAKE_FLOAT_HEXVAL((s), (e), (m)); \
			memcpy(&(f), &temp, sizeof(f)); \
		} while (0)

#define DTOA_PRECISION 8
#define DTOA_PRECISION_MAX 1e8
typedef uint32_t dtoa_fixnum_t;

#define DOUBLE_SIGN_HEXVAL(hexval) ((hexval) >> 31) // 1bit
#define DOUBLE_CLEARSIGN_HEXVAL(hexval) ((hexval) & 0x7fffffff)
#define DOUBLE_EXPONENT_HEXVAL(hexval) ((((hexval) >> 23) & 0xff) - 127) // 8bits
#define DOUBLE_MANTISSA_HEXVAL(hexval) ((hexval) & 0x7fffff) // 23bits
#define MAKE_DOUBLE_HEXVAL(s, e, m) ((((uint32_t)(s) & 1) << 31) | (((uint32_t)((e) + 127) & 0xff) << 23) | ((uint32_t)(m) & 0x7fffff))
#define MAKE_DOUBLE(d, s, e, m) \
		do { \
			uint32_t temp = MAKE_DOUBLE_HEXVAL((s), (e), (m)); \
			memcpy(&(d), &temp, sizeof(d)); \
		} while (0)

char *ftoa(float value);
char *dtoa(double value);
char *ltoa(long value);
char *hexstr(uint32_t value, uint8_t width);

【strconv.c】

#include <stdint.h>
#include <string.h>
#include "strconv.h"

static const float float_table[31] = {
	1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, 1.0e6f, 1.0e7f, 1.0e8f, 
	1.0e9f, 1.0e10f, 1.0e11f, 1.0e12f, 1.0e13f, 1.0e14f, 1.0e15f, 1.0e16f, 
	1.0e17f, 1.0e18f, 1.0e19f, 1.0e20f, 1.0e21f, 1.0e22f, 1.0e23f, 1.0e24f, 
	1.0e25f, 1.0e26f, 1.0e27f, 1.0e28f, 1.0e29f, 1.0e30f, 1.0e31f
};
static const float float_table_2[1] = {1.0e32f};
static const double double_table[31] = {
	1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 
	1.0e9, 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 
	1.0e17, 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 
	1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, 1.0e30, 1.0e31
};
static const double double_table_2[1] = {1.0e32};
static char strconv_str[50];

char *ftoa(float value)
{
	char *p = strconv_str;
	float num;
	ftoa_fixnum_t fixnum;
	int16_t e, k, a, b, i;
	uint8_t negative;
	uint32_t num_hexval, value_hexval;

	memcpy(&value_hexval, &value, sizeof(value_hexval));
	negative = FLOAT_SIGN_HEXVAL(value_hexval);

	e = FLOAT_EXPONENT_HEXVAL(value_hexval);
	if (e == -127)
	{
		if (!negative)
			strcpy(strconv_str, "0");
		else
			strcpy(strconv_str, "-0");
		return strconv_str;
	}
	else if (e == 128)
	{
		if (FLOAT_MANTISSA_HEXVAL(value_hexval) == 0)
		{
			if (!negative)
				strcpy(strconv_str, "inf");
			else
				strcpy(strconv_str, "-inf");
		}
		else
		{
			if (!negative)
				strcpy(strconv_str, "nan");
			else
				strcpy(strconv_str, "-nan");
		}
		return strconv_str;
	}
	e = ((int32_t)e * 19728) / 65536;
	k = -(FTOA_PRECISION - (e + 1));
	num_hexval = FLOAT_CLEARSIGN_HEXVAL(value_hexval);
	memcpy(&num, &num_hexval, sizeof(num));
	if (k > 0)
	{
		a = k / 32;
		b = k % 32;
		if (a != 0)
			num /= float_table_2[a - 1];
		if (b != 0)
			num /= float_table[b - 1];
	}
	else if (k < 0)
	{
		a = (-k) / 32;
		b = (-k) % 32;
		if (a != 0)
			num *= float_table_2[a - 1];
		if (b != 0)
			num *= float_table[b - 1];
	}
	num += 0.5f;

	if (num >= FTOA_PRECISION_MAX)
	{
		e++;
		k++;
		num /= 10;
	}
	
	memcpy(&num_hexval, &num, sizeof(num_hexval));
	fixnum = FLOAT_MANTISSA_HEXVAL(num_hexval) | (1ul << 15);
	i = FLOAT_EXPONENT_HEXVAL(num_hexval) - 15;
	if (i > 0)
		fixnum <<= i; 
	else if (i < 0)
		fixnum >>= -i;
		
	if (negative)
		*p++ = '-';
	if (e + 1 < 1)
	{
		*p++ = '0';
		*p++ = '.';
		while (e + 1 < 0)
		{
			*p++ = '0';
			e++;
		}
		i = FTOA_PRECISION;
	}
	else if (e + 1 < FTOA_PRECISION)
		i = FTOA_PRECISION + 1;
	else
		i = e + 1;
	p[i--] = '\0';
	while (i >= 0)
	{
		if (i >= FTOA_PRECISION && e + 1 >= FTOA_PRECISION)
			p[i--] = '0';
		else
		{
			if (i == e + 1 && i != 0)
				p[i--] = '.';
			p[i--] = '0' + fixnum % 10;
			fixnum /= 10;
		}
	}

	if (e + 1 < FTOA_PRECISION)
	{
		i = FTOA_PRECISION;
		if (p[i] == '\0')
			i--;
		while (i >= 0 && p[i] == '0')
		{
			p[i] = '\0';
			i--;
		}
		if (i >= 0 && p[i] == '.')
			p[i] = '\0';
	}
	return strconv_str;
}

char *dtoa(double value)
{
	char *p = strconv_str;
	double num;
	dtoa_fixnum_t fixnum;
	int16_t e, k, a, b, i;
	uint8_t negative;
	uint32_t num_hexval, value_hexval;

	memcpy(&value_hexval, &value, sizeof(value_hexval));
	negative = DOUBLE_SIGN_HEXVAL(value_hexval);

	e = DOUBLE_EXPONENT_HEXVAL(value_hexval);
	if (e == -127)
	{
		if (!negative)
			strcpy(strconv_str, "0");
		else
			strcpy(strconv_str, "-0");
		return strconv_str;
	}
	else if (e == 128)
	{
		if (DOUBLE_MANTISSA_HEXVAL(value_hexval) == 0)
		{
			if (!negative)
				strcpy(strconv_str, "inf");
			else
				strcpy(strconv_str, "-inf");
		}
		else
		{
			if (!negative)
				strcpy(strconv_str, "nan");
			else
				strcpy(strconv_str, "-nan");
		}
		return strconv_str;
	}
	e = ((int32_t)e * 19728) / 65536;
	k = -(DTOA_PRECISION - (e + 1));
	num_hexval = DOUBLE_CLEARSIGN_HEXVAL(value_hexval);
	memcpy(&num, &num_hexval, sizeof(num));
	if (k > 0)
	{
		a = k / 32;
		b = k % 32;
		if (a != 0)
			num /= double_table_2[a - 1];
		if (b != 0)
			num /= double_table[b - 1];
	}
	else if (k < 0)
	{
		a = (-k) / 32;
		b = (-k) % 32;
		if (a != 0)
			num *= double_table_2[a - 1];
		if (b != 0)
			num *= double_table[b - 1];
	}
	num += 0.5;

	if (num >= DTOA_PRECISION_MAX)
	{
		e++;
		k++;
		num /= 10;
	}
	
	memcpy(&num_hexval, &num, sizeof(num_hexval));
	fixnum = DOUBLE_MANTISSA_HEXVAL(num_hexval) | (1ul << 23);
	i = DOUBLE_EXPONENT_HEXVAL(num_hexval) - 23;
	if (i > 0)
		fixnum <<= i; 
	else if (i < 0)
		fixnum >>= -i;
		
	if (negative)
		*p++ = '-';
	if (e + 1 < 1)
	{
		*p++ = '0';
		*p++ = '.';
		while (e + 1 < 0)
		{
			*p++ = '0';
			e++;
		}
		i = DTOA_PRECISION;
	}
	else if (e + 1 < DTOA_PRECISION)
		i = DTOA_PRECISION + 1;
	else
		i = e + 1;
	p[i--] = '\0';
	while (i >= 0)
	{
		if (i >= DTOA_PRECISION && e + 1 >= DTOA_PRECISION)
			p[i--] = '0';
		else
		{
			if (i == e + 1 && i != 0)
				p[i--] = '.';
			p[i--] = '0' + fixnum % 10;
			fixnum /= 10;
		}
	}

	if (e + 1 < DTOA_PRECISION)
	{
		i = DTOA_PRECISION;
		if (p[i] == '\0')
			i--;
		while (i >= 0 && p[i] == '0')
		{
			p[i] = '\0';
			i--;
		}
		if (i >= 0 && p[i] == '.')
			p[i] = '\0';
	}
	return strconv_str;
}

char *ltoa(long value)
{
	char temp;
	uint8_t i, n, start = 0;
	
	if (value == 0)
	{
		strconv_str[0] = '0';
		strconv_str[1] = '\0';
	}
	else
	{
		if (value < 0)
		{
			strconv_str[0] = '-';
			start = 1;
		}
		else
			value = -value;
		
		for (i = start; value != 0; i++)
		{
			strconv_str[i] = '0' + (-(value % 10));
			value /= 10;
		}
		strconv_str[i] = '\0';
		
		n = i - start;
		for (i = 0; i < n / 2; i++)
		{
			temp = strconv_str[start + i];
			strconv_str[start + i] = strconv_str[start + n - i - 1];
			strconv_str[start + n - i - 1] = temp;
		}
	}
	return strconv_str;
}

char *hexstr(uint32_t value, uint8_t width)
{
	char ch;
	uint8_t i, j = 2;
	uint8_t ignore = 1;
	
	strconv_str[0] = '0';
	strconv_str[1] = 'x';
	for (i = 0; i < 8; i++)
	{
		ch = (value >> 28) & 0xff;
		value <<= 4;
		if (ignore && ch == 0 && 8 - i > width)
		{
			continue;
		}
		
		ignore = 0;
		if (ch >= 0 && ch <= 9)
		{
			ch += '0';
		}
		else if (ch >= 10 && ch <= 15)
		{
			ch += 'a' - 10;
		}
		strconv_str[j] = ch;
		j++;
	}
	strconv_str[j] = '\0';
	return strconv_str;
}

【uart.h】

void dump_data(const void *data, int len);
void uart_init();
void uart_send(uint8_t data);
void uart_send_char(char ch);
void uart_send_string(const char *s);
void uart_wait_tx();

【uart.c】

#include <stdint.h>
#include <BA45F5650.h>
#include "uart.h"

void dump_data(const void *data, int len)
{
	const char *list = "0123456789ABCDEF";
	const uint8_t *p = data;
	
	while (len--)
	{
		uart_send_char(list[*p >> 4]);
		uart_send_char(list[*p & 15]);
		p++;
	}
	uart_send_char('\n');
}

void uart_init()
{
	// select PA6 as UART_RX
	_pas15 = 1;
	_pas14 = 1;
	_ifs11 = 1;
	_ifs10 = 0;
	_papu6 = 1; // pull-up
	// select PA3 as UART_TX
	_pas07 = 1;
	_pas06 = 0;
	
	// change HICR frequency from 2MHz to 8MHz
	_hirc1 = 1;
	_hirc0 = 0;
	while (!_hircf);
	
	// set baudrate to 38400
	// 2MHz/(16*(12+1))->9615.385
	// 8MHz/(16*(12+1))->38461.538
	_brgh = 1;
	_brg = 12;
	
	// enable UART
	_uarten = 1;
	_rxen = 1;
	_txen = 1;
}

void uart_send(uint8_t data)
{
	while (!_txif);
	_txr_rxr = data;
}

void uart_send_char(char ch)
{
	if (ch == '\n')
		uart_send('\r');
	uart_send(ch);
}

void uart_send_string(const char *s)
{
	while (*s)
		uart_send_char(*s++);
}

void uart_wait_tx()
{
	while (!_tidle);
}

【main.c】

#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <BA45F5650.h>
#include "strconv.h"
#include "uart.h"

static void test_float()
{
	float value;
	
	uart_send_string(ftoa(1.245f));
	uart_send_string(" ");
	uart_send_string(ftoa(-9.36f));
	uart_send_string(" ");
	uart_send_string(ftoa(1.78f));
	uart_send_string(" ");
	uart_send_string(ftoa(1456.0f));
	uart_send_string(" ");
	uart_send_string(ftoa(0.00075f));
	uart_send_string(" ");
	uart_send_string(ftoa(0.0000491f));
	uart_send_string("\n");
	
	uart_send_string(ftoa(2.57e14f));
	uart_send_string(" ");
	uart_send_string(ftoa(9.46e37f));
	uart_send_string("\n");
	
	uart_send_string(ftoa(0.0f));
	uart_send_string(" ");
	uart_send_string(ftoa(-0.0f));
	uart_send_string(" ");
	MAKE_FLOAT(value, 0, -127, 0);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 1, -127, 0);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 0, -127, 7ul << 12);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 1, -127, 7ul << 12);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 0, 128, 0);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 1, 128, 0);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 0, 128, 7ul << 12);
	uart_send_string(ftoa(value));
	uart_send_string(" ");
	MAKE_FLOAT(value, 1, 128, 7ul << 12);
	uart_send_string(ftoa(value));
	uart_send_string("\n");
}

static void test_double()
{
	double value;
	
	uart_send_string(dtoa(1.245));
	uart_send_string(" ");
	uart_send_string(dtoa(-9.36));
	uart_send_string(" ");
	uart_send_string(dtoa(1234567.0));
	uart_send_string(" ");
	uart_send_string(dtoa(1048576.0));
	uart_send_string(" ");
	uart_send_string(dtoa(-0.0000125));
	uart_send_string(" ");
	uart_send_string(dtoa(-0.000379));
	uart_send_string("\n");
	
	uart_send_string(dtoa(3.1415926e17));
	uart_send_string(" ");
	uart_send_string(dtoa(1.42857e38));
	uart_send_string("\n");
	
	uart_send_string(dtoa(0.0));
	uart_send_string(" ");
	uart_send_string(dtoa(-0.0));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 0, -127, 0);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 1, -127, 0);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 0, -127, 7ul << 20);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 1, -127, 7ul << 20);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 0, 128, 0);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 1, 128, 0);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 0, 128, 7ul << 20);
	uart_send_string(dtoa(value));
	uart_send_string(" ");
	MAKE_DOUBLE(value, 1, 128, 7ul << 20);
	uart_send_string(dtoa(value));
	uart_send_string("\n");
}

void system_reset()
{
	// write an incorrect value to _wdtc to reset the system
	_wdtc = 0;
}

void main()
{
	uint8_t ch;
	
	uart_init();
	uart_send_string("BA45F5650 UART\n");
	
	uart_send_string("sizeof(float)=");
	uart_send_string(ltoa(sizeof(float)));
	uart_send_string(", ");
	uart_send_string("sizeof(double)=");
	uart_send_string(ltoa(sizeof(double)));
	uart_send_string("\n");
	
	test_float();
	test_double();
	
	while (1)
	{
		// the watchdog is enabled by default and cannot be disabled by software
		// therefore, the watchdog timer must be cleared periodically
		_clrwdt(); // this also clears _to and _pdf bit
		
		// receive from UART
		if (_rxif)
		{
			ch = _txr_rxr;
			if (isprint(ch))
			{
				uart_send_string("UART character: ");
				uart_send(ch);
				uart_send_string("\n");
				
				switch (ch)
				{
				case 'G':
					// Green LED control
					if (_pcc0) // Is the pin in input mode?
					{
						// set led pin to output mode
						_pcc0 = 0;
						_pc0 = 0;
					}
					else
					{
						// led on/off
						_pc0 = ~_pc0;
					}
					break;
				case 'R':
					// Red LED control
					if (_pcc4)
					{
						_pcc4 = 0;
						_pc4 = 0;
					}
					else
						_pc4 = ~_pc4;
					break;
				case 'r':
					uart_send_string("RESET\n");
					uart_wait_tx();
					system_reset();
					break;
				case 'W':
					// Warning LED control
					if (_pbc1)
					{
						_pbc1 = 0;
						_pb1 = 0;
					}
					else	
						_pb1 = ~_pb1;
					break;
				case 'w':
					uart_send_string("LVRF=");
					uart_send_string(ltoa(_lvrf)); // low voltage reset flag
					uart_send_string(", WRF=");
					uart_send_string(ltoa(_wrf)); // flag of software reset triggered by incorrectly writing _wdtc
					uart_send_string(", TO=");
					uart_send_string(ltoa(_to)); // watchdog reset flag (read-only)
					uart_send_string(", PDF=");
					uart_send_string(ltoa(_pdf)); // halt flag (read-only)
					uart_send_string("\n");
					
					// the following two bits can be cleared only by software
					_lvrf = 0;
					_wrf = 0;
					break;
				}
			}
			else
			{
				uart_send_string("UART data: ");
				uart_send_string(hexstr(ch, 2));
				uart_send_string("\n");
			}
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/701016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于肺部图片与文本信息的多模态模型架构

文章题为 「A transformer-based representation learning model with unified processing of multimodal input for clinical diagnostics」 https://www.nature.com/articles/s41551-023-01045-x &#xff08;arXiv版链接: https://arxiv.org/abs/2306.00864&#xff09; htt…

2020年全国硕士研究生入学统一考试管理类专业学位联考数学试题——解析版

2020 级考研管理类联考数学真题 一、问题求解&#xff08;本大题共 15 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09;下列每题给出 5 个选项中&#xff0c;只有一个是符合要求的&#xff0c;请在答题卡上将所选择的字母涂黑。 1、某产品去年涨价 10%&#xf…

备战2024秋招面试题-Vue的框架原理

前言&#xff1a; \textcolor{Green}{前言&#xff1a;} 前言&#xff1a; &#x1f49e;快秋招了&#xff0c;那么这个专栏就专门来记录一下&#xff0c;同时呢整理一下常见面试题 &#x1f49e;部分题目来自自己的面试题&#xff0c;部分题目来自网络整理 给我冲 学习目标&am…

阿里云服务器ECS介绍_云主机_服务器托管_弹性计算

阿里云服务器安全可靠、弹性可伸缩&#xff0c;CPU可选256核、内存选到3072GB&#xff0c;云服务器ECS规格通用型、计算型、内存型、通用算力型、裸金属、GPU、大数据等ECS实例规格&#xff0c;公网带宽可选到200M&#xff0c;绑定弹性公网EIP带宽可达1000M&#xff0c;共享带宽…

9.外部中断

1.中断概念&#xff1a; &#xff08;1&#xff09;STM32的每个IO口都可以作为外部中断输入&#xff1b; &#xff08;2&#xff09;stm32的中断控制器支持19个外部中断/事件请求 线0~15&#xff1a;对应外部IO口的输入中断&#xff1b;线16&#xff1a;连接到PVD输出&#…

基于jsp+Servlet+mysql的汽车销售系统

基于jspServletmysql的汽车销售系统 一、系统介绍二、功能展示1.项目骨架2.登录界面3.首页4.购物车5.添加车辆6、编辑车辆信息 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目类型&#xff1a;Java web项目 项目名称&#xff1a;基于JSPServlet的汽车销售系统 项目架…

新后端漏洞之----SSRF漏洞(服务端请求伪造)

笔记 前言SSRF漏洞概述SSRF漏洞检测与挖掘SSRF漏洞的回显分类SSRF漏洞利用SSRF漏洞防御 前言 这几天各种技术面试接踵而至&#xff0c;压得我喘不过气了&#xff01;然后面试官问了我这个SSRF漏洞原理和利用方式以及防御手段&#xff0c;当然同时还问了好几个Top10漏洞&#x…

【React】React Hooks解析

React Hooks解析 React 16.8 认识和体验Hooks 为什么需要Hook? Hook是 React 16.8 的新增特性&#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性&#xff08;比如生命周期&#xff09; 我们先来思考一下class组件相对于函数式组件有什么优势&…

企业知识竞赛答题pk活动怎么做?

随着互联网的发展&#xff0c;越来越多的企事业单位开始利用答题小程序进行线上PK答题活动&#xff0c;目的在于组织员工学习企业文化或是进行专题答题活动以适应时代的进步。其中最主流的有&#xff1a;网络安全知识竞赛、安全生产知识竞赛、企业文化PK答题竞赛、红色党史知识…

js中的树以及优先遍历!

树 什么是树&#xff1f; 在生活中&#xff0c;大家对树肯定不陌生&#xff0c;小朋友都知道树不就是一类植物嘛&#xff0c;不管在任何地方都有各种各样的树。但是在计算机科学里面树是什么呢&#xff1f;一种分层数据的抽象模型&#xff0c;在我们前端工作中无处不在。在 J…

攻克数据中心液冷升级三大难题,宁畅推出“无忧焕液计划“

近年来&#xff0c;在政策引导、市场需求、技术升级等多种因素影响下&#xff0c;数据中心正在迎来发展新机遇。如何部署节能技术并兼顾算效、能耗、成本&#xff0c;成为考验数据中心建设与运营者的关键。 在此背景下&#xff0c;宁畅于6月28日召开“无忧焕液 智惠升级”媒体沟…

epoll反应堆

// epoll基于非阻塞I/O事件驱动 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/epoll.h> #inclu…

利用Python分析快手APP全国大学生用户数据

背景 背景&#xff1a;利用Python分析快手APP全国大学生用户数据&#xff0c;发现&#xff1a; 哪个学校的学生最喜欢使用快手APP Android、IOS、PC三大平台用户占比份额 全国哪些城市(学校所在地)的学生使用频次最高 全国哪些省份的生源最喜欢使用快手APP … 数据&#xff1a…

形式化验证,Gap-free Processor Verifification by S2QED and Property Generation(一)

目录 一、Article:文献出处&#xff08;方便再次搜索&#xff09; &#xff08;1&#xff09;作者 &#xff08;2&#xff09;文献题目 &#xff08;3&#xff09;文献时间 &#xff08;4&#xff09;引用 二、Data:文献数据&#xff08;总结归纳&#xff0c;方便理解&am…

不漏测,测试人员的极致追求

一、什么是漏测&#xff1f; 具体地说&#xff0c;什么是测试漏测&#xff1f;测试漏测是指软件产品在测试结束后出现了在测试过程中没有被发现的bug。 我们知道&#xff0c;漏测是每一个软件测试者最头疼的事&#xff0c;一旦出现漏测&#xff1a; 首先给客户带来了非常不好…

C语言-基础语法学习-3 二级指针

目录 二级指针二级指针的定义和声明二级指针的初始化二级指针的使用二级指针和函数参数二级指针和动态内存分配数组指针二维数组二维数组的初始化二维数组与指针二维数组的遍历 二级指针 当涉及到多级指针时&#xff0c;C语言的灵活性和强大的指针功能可以得到充分的发挥。二级…

Xshell弹窗:需要Xmanager软件来处理X11转发请求(解决办法:关闭X11转发)

文章目录 问题背景问题分析什么是X11转发&#xff1f;分析原因&#xff08;没分析出来&#xff09; 解决办法&#xff08;关闭X11转发&#xff09;参考文章 问题背景 今天我在ubuntu服务器上用python flask框架做了个http服务程序&#xff0c;我用xshell连接服务器并执行该服务…

对话 | 中国团队首次完成“赫兹速率”的城域量子隐形传态

光子盒研究院 近日&#xff0c;电子科技大学郭光灿院士团队周强研究组与中科院上海微系统所尤立星团队合作&#xff0c;在电子科技大学“银杏一号”城域量子互联网方面取得了重大进展。 “银杏一号”城域量子互联网建设场地鸟瞰图和设计概念图。展示了一个量子隐形传态系统&…

神策(Android)- 在曝光采集基础上学习项目架构

开篇的时候我就在想这篇blog到底有没有意义&#xff1f;因为本身使用的就是神策提供的功能&#xff0c;同时神策也提供了很完善的文档&#xff0c;而唯一要我们做的也仅仅是将它正确的集成到项目内&#xff0c;并且随着版本升级&#xff0c;文档肯定也会有一定变更… 不过&…

STM32微控制器:现状与竞争力的评估

STM32是意法半导体&#xff08;STMicroelectronics&#xff09;开发的一系列32位ARM Cortex-M微控制器。它们被广泛用于嵌入式系统开发&#xff0c;并在许多应用领域中得到了广泛应用&#xff0c;包括消费电子、工业自动化、汽车行业和物联网等。 尽管我无法提供最新的市场趋势…