最近在项目中用到了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");
}
}
}
}