C 显示以前接收到的UART值
这对熟悉C语言的人来说应该很容易回答。我想在LCD上显示变量的先前值(微控制器上UART(RS-232)的接收寄存器)。这是我当前的实现,工作正常。但是我想知道是否有一种方法可以减少我中断程序的时间。目前,外设被配置为在UART馈送中接收到一个新字符时立即跳转到中断例程。有人吗C 显示以前接收到的UART值,c,microcontroller,microchip,uart,C,Microcontroller,Microchip,Uart,这对熟悉C语言的人来说应该很容易回答。我想在LCD上显示变量的先前值(微控制器上UART(RS-232)的接收寄存器)。这是我当前的实现,工作正常。但是我想知道是否有一种方法可以减少我中断程序的时间。目前,外设被配置为在UART馈送中接收到一个新字符时立即跳转到中断例程。有人吗 //Initialization char U1RX_data = '\0'; char p0_U1RX_data = '\0'; char p1_U1RX_data = '\0'; char p2_U1RX_data
//Initialization
char U1RX_data = '\0';
char p0_U1RX_data = '\0';
char p1_U1RX_data = '\0';
char p2_U1RX_data = '\0';
char p3_U1RX_data = '\0';
char p4_U1RX_data = '\0';
char p5_U1RX_data = '\0';
char p6_U1RX_data = '\0';
char p7_U1RX_data = '\0';
char U1buf[] = {p7_U1RX_data, p6_U1RX_data, p5_U1RX_data,
p4_U1RX_data, p3_U1RX_data, p2_U1RX_data,
p1_U1RX_data, p0_U1RX_data, U1RX_data, '\0'};
disp_string(-61, 17, 1, U1buf); //X, Y, mode, string
void _U1RXInterrupt(void){
p7_U1RX_data = p6_U1RX_data;
p6_U1RX_data = p5_U1RX_data;
p5_U1RX_data = p4_U1RX_data;
p4_U1RX_data = p3_U1RX_data;
p3_U1RX_data = p2_U1RX_data;
p2_U1RX_data = p1_U1RX_data;
p1_U1RX_data = p0_U1RX_data;
p0_U1RX_data = U1RX_data;
U1RX_data = U1RXREG;
IFS0bits.U1RXIF = 0;
}
您可以在中断中使用
memmove
,如下所示:
void _U1RXInterrupt(void)
{
memmove(&U1Buf[0], &U1Buf[1], 7);
U1Buf[7] = U1RX_data;
...
}
#define UART_BUF_SIZE 16
char uart_buf[UART_BUF_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0};
char uart_buf_index = 0;
这将取代您当前手动执行的任务,并且更加惯用
我希望我能正确地理解你;要点是使用
memmove
将缓冲区下移一个字节。另外,当目标缓冲区和源缓冲区重叠时,使用memmove
而不是memcpy
非常重要,如本例所示。您可以在中断中使用memmove
,如下所示:
void _U1RXInterrupt(void)
{
memmove(&U1Buf[0], &U1Buf[1], 7);
U1Buf[7] = U1RX_data;
...
}
#define UART_BUF_SIZE 16
char uart_buf[UART_BUF_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0};
char uart_buf_index = 0;
这将取代您当前手动执行的任务,并且更加惯用
我希望我能正确地理解你;要点是使用
memmove
将缓冲区下移一个字节。另一方面,当目标缓冲区和源缓冲区重叠时,使用memmove
而不是memcpy
是很重要的,如本例所示。正如Emerick指出的那样,memmove()
如果您有权访问它,它将很好地工作。如果没有,只需从Google获取一个简单的实现,它不应该占用太多的指令内存
微控制器上的时钟频率是多少?另一件需要考虑的事情是,如果你的时钟速度明显高于你的波特率,那么这些事情很多都不会成为问题。例如,如果你的时钟速度是16兆赫,你真的不必担心创造世界上最短的ISR,只要你不做任何疯狂的计算密集型的事情。此外,如果系统的计时速度明显快于波特率,轮询也是一种选择
编辑:我刚刚想到的另一个选项,使用中断
您可以将缓冲区存储为字符数组,然后保留下一个空插槽的全局索引,如下所示:
void _U1RXInterrupt(void)
{
memmove(&U1Buf[0], &U1Buf[1], 7);
U1Buf[7] = U1RX_data;
...
}
#define UART_BUF_SIZE 16
char uart_buf[UART_BUF_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0};
char uart_buf_index = 0;
然后在ISR中,您所需要做的就是将新字节转储到索引指向的存储桶中,并增加索引。当起始位置围绕缓冲区向后旋转时,这将自动覆盖缓冲区中最旧的字符
void my_isr()
{
uart_buf[uart_buf_index] = get_uart_byte();
uart_buf_index = (uart_buf_index + 1) % UART_BUF_SIZE;
}
基本上,在这一点上,您有一个具有旋转起始位置的缓冲区,但它可以避免您每次ISR都要移动16字节的内存。诀窍在于把它读出来,因为你必须考虑到环绕
char i;
for (i = uart_buf_index; i < UART_BUF_SIZE; i++)
{
lcd_write_byte(uart_buf[i]);
}
for (i = 0; i < uart_buf_index; i++)
{
lcd_write_byte(uart_buf[i]);
}
chari;
对于(i=uart\u buf\u索引;i
正如Emerick所指出的,memmove()
如果您有权访问它,它将很好地工作。如果没有,只需从Google获取一个简单的实现,它不应该占用太多的指令内存
微控制器上的时钟频率是多少?另一件需要考虑的事情是,如果你的时钟速度明显高于你的波特率,那么这些事情很多都不会成为问题。例如,如果你的时钟速度是16兆赫,你真的不必担心创造世界上最短的ISR,只要你不做任何疯狂的计算密集型的事情。此外,如果系统的计时速度明显快于波特率,轮询也是一种选择
编辑:我刚刚想到的另一个选项,使用中断
您可以将缓冲区存储为字符数组,然后保留下一个空插槽的全局索引,如下所示:
void _U1RXInterrupt(void)
{
memmove(&U1Buf[0], &U1Buf[1], 7);
U1Buf[7] = U1RX_data;
...
}
#define UART_BUF_SIZE 16
char uart_buf[UART_BUF_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0};
char uart_buf_index = 0;
然后在ISR中,您所需要做的就是将新字节转储到索引指向的存储桶中,并增加索引。当起始位置围绕缓冲区向后旋转时,这将自动覆盖缓冲区中最旧的字符
void my_isr()
{
uart_buf[uart_buf_index] = get_uart_byte();
uart_buf_index = (uart_buf_index + 1) % UART_BUF_SIZE;
}
基本上,在这一点上,您有一个具有旋转起始位置的缓冲区,但它可以避免您每次ISR都要移动16字节的内存。诀窍在于把它读出来,因为你必须考虑到环绕
char i;
for (i = uart_buf_index; i < UART_BUF_SIZE; i++)
{
lcd_write_byte(uart_buf[i]);
}
for (i = 0; i < uart_buf_index; i++)
{
lcd_write_byte(uart_buf[i]);
}
chari;
对于(i=uart\u buf\u索引;i
我将创建一个先前值的数组,并将其视为循环缓冲区。然后,中断例程简单地将新值记录在下一个插槽中,覆盖上一个值,并增加索引
#define DIM(x) (sizeof(x)/sizeof(*(x)))
static int index = 0;
static char uart[8];
void _U1RXInterrupt(void){
if (++index >= DIM(uart))
index = 0;
uart[index] = U1RXREG;
IFS0bits.U1RXIF = 0;
}
int uart_value(unsigned n)
{
int i = index + DIM(uart) - (n % DIM(uart));
if (i > DIM(uart))
i -= DIM(uart);
return(uart[i]);
}
我假设是同步的、非线程的操作;如果必须处理多线程,那么就需要保护索引变量不受并发访问。对于缓冲区满之前的最后一次读取,它也返回零。等等。如果您对编码有信心,也可以删除模运算。我将创建一个先前值的数组,并将其视为循环缓冲区。然后,中断例程简单地将新值记录在下一个插槽中,覆盖上一个值,并增加索引
#define DIM(x) (sizeof(x)/sizeof(*(x)))
static int index = 0;
static char uart[8];
void _U1RXInterrupt(void){
if (++index >= DIM(uart))
index = 0;
uart[index] = U1RXREG;
IFS0bits.U1RXIF = 0;
}
int uart_value(unsigned n)
{
int i = index + DIM(uart) - (n % DIM(uart));
if (i > DIM(uart))
i -= DIM(uart);
return(uart[i]);
}
我假设是同步的、非线程的操作;如果必须处理多线程,那么就需要保护索引变量不受并发访问。对于缓冲区满之前的最后一次读取,它也返回零。等等。如果您对自己的编码有信心,也可以删除模运算。您始终可以制作一个固定长度的循环缓冲区
char buffer[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',);
char position = 0;
/* useable if you have a version of disp_string that takes a "number of chars"*/
char buffer_nprint()
{
/* print from position to the end of the buffer*/
disp_string(-61, 17, 1, &buffer[position], 8 - position);
if (position > 0)
{
/* now print from start of buffer to position */
disp_string(-61, 17, 1, buffer, position);
}
}
/* if you _don't_ have a version of disp_string that takes a "number of chars"
and are able to do stack allocations*/
char buffer_print()
{
char temp[9];
temp[8] = '/0';
memcpy(temp, &buffer[position], 8 - position);
memcpy(temp, buffer, position);
temp[8] = '/0';
disp_string(-61, 17, 1, temp);
}
char buffer_add(char new_data)
{
char old_data = buffer[position];
buffer[position] = new_data;
position = ((position + 1) & 8);
}
void _U1RXInterrupt(void)
{
buffer_add(U1RXREG);
IFS0bits.U1RXIF = 0;
}
您始终可以制作固定长度的循环缓冲区
char buffer[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',);
char position = 0;
/* useable if you have a version of disp_string that takes a "number of chars"*/
char buffer_nprint()
{
/* print from position to the end of the buffer*/
disp_string(-61, 17, 1, &buffer[position], 8 - position);
if (position > 0)
{
/* now print from start of buffer to position */
disp_string(-61, 17, 1, buffer, position);
}
}
/* if you _don't_ have a version of disp_string that takes a "number of chars"
and are able to do stack allocations*/
char buffer_print()
{
char temp[9];
temp[8] = '/0';
memcpy(temp, &buffer[position], 8 - position);
memcpy(temp, buffer, position);
temp[8] = '/0';
disp_string(-61, 17, 1, temp);
}
char buffer_add(char new_data)
{
char old_data = buffer[position];
buffer[position] = new_data;
position = ((position + 1) & 8);
}
void _U1RXInterrupt(void)
{
buffer_add(U1RXREG);
IFS0bits.U1RXIF = 0;
}
由于它是一个dspic,您可能想看看处理uart DMA的示例ce214和ce114 转到此处搜索“uart”: DMA方法是面向块的,并且只有一个中断