我使用了Atmega328PμC来获取UART上的字符串并将其转换为int
。
我尝试使用atoi()
函数或sscanf()
来转换它,但它们需要很长时间才能转换,以便它们阻止中断。
如果我停止转换并且仅通过UART接收所有符号都被传输但是如果我在接收到某些传输字符后转换则丢失。
有没有办法加快转换以阻止RX中断?
答案 0 :(得分:0)
如果您需要将多字符数转换为整数,则需要使用缓冲区。有循环缓冲区使用的例子:
#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时钟减少了运行时间代码并增加了空闲时间。
通过减少周边时钟减少了中断的频率,增加了空闲时间。
总之必须使用空闲时间进行省电。
答案 1 :(得分:0)
是的,该函数在主循环中运行,并将字符复制出缓冲区,缓冲区填充在中断例程中。在字符串中检测到\ n后,它会使用sscanf或char将字符串转换为值。我首先使用非常慢的波特率,然后使用非常快的波特率。还有两个中断例程(对于100us的时序和一个用于pwm驱动器的时序)。我试图取出这些例程的代码来加速它们并且它成功了。现在,中断例程获取uart传输的每个字符。现在我正在实现一种算法,在不使用sscanf的情况下将字符串转换为值,因为性能问题。使用imbearr与-0x30的算法应该可以正常工作。