我使用 Atmega328P µC 通过 UART 获取字符串并将其转换为 int
。
我尝试使用atoi()
函数或sscanf()
来转换它,但它们需要很长时间才能转换,因此它们会阻塞中断。
如果我停止转换并仅通过 UART 接收,则所有符号都会传输,但如果我在接收后进行转换,则会丢失一些传输字符。
有什么方法可以加快转换速度以停止阻塞 RX 中断吗?
最佳答案
如果您需要将多字符数字转换为整数,则需要使用缓冲区。循环缓冲区使用示例:
#define BUF_LEN 128
#define BUF_MSK (BUF_LEN-1)
uint8_t buf[BUF_LEN], b_in = 0, b_out = 0;
void usart_irq_handler(void)
{
buf[b_in&BUF_MSK] = USART_DATA_REG;
b_in++;
}
int main(void)
{
uint8_t tmp;
while (b_in!=b_out) {
tmp = buf[b_out&BUF_MSK];
b_out++;
// parse here
}
}
如果您需要转换单个字符数字,您可以不使用缓冲区(但如果 USART 频率不低于 CPU 频率,则不建议使用)。对于 ASCII 编码的接收字符,每个数字的值为 0x30..0x39。如果收到使用其他字符集编码的字符,您需要引用他们的表。
uint8_t num = USART_DATA_REG - 0x30;
if (num >= 0 && num <= 9) {
// is number
}
编辑1 [由于来自OP的新信息] 为了将十进制数从字符串转换为整数我使用这个函数:
uint32_t parse_num(uint8_t * ptr)
{
uint32_t res = (uint32_t)0x0;
uint8_t chr = 0x0, pchr = 0xA;
while (*ptr != (uint8_t)0x0) {
chr = (uint8_t)(*ptr - (uint8_t)0x30);
if (chr < 0xA) {
res *= (uint32_t) 0xA;
res += (uint32_t) chr;
} else {
if (pchr < 0xA) break;
}
pchr = chr;
ptr++;
}
return res;
}
它跳过非数字字符并转换第一个找到的数字,但不返回解析缓冲区的最终位置。您可以根据需要进行修改。
编辑2 [由于与OP聊天] 关于处理器时间管理的好方法:
下面的图片(来自此answer)说明了程序中的正常处理器时序:
因此,中断处理程序时间越短 - 其他处理程序成功的可能性就越大,执行主流程的时间就越多。
通过增加 MCU 时钟可以减少代码的运行时间并增加空闲时间。
通过减少外围时钟可以降低外围中断的频率并增加空闲时间。
总之必须利用空闲时间来节省电量。
关于C Atmega328P String 到 Int 转换 block RX 中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36886920/