我写了一个程序,在两种模式下从atmega 2560读取采样值,一种是单采样模式,为用户选择的每个通道打印一个采样,另一种是批量模式,为每个选择的通道填充一个采样缓冲区,当所有这些缓冲区都满了时,将其打印在txt上。
我使用一个头0x 55 aa来宣布数据即将到来,如果我收到它,我会用我需要的信息填充结构体:序列号、通道、样本数。然后,我使用for循环来填充我感兴趣的缓冲区(它在continous模式下只执行一个循环,因为struct中的样本数为1)
int n_read = fscanf(f, "%d", & key); //we read 4 bytes and see if it equals the key
if (key == 0x55aa) {
n_read = fscanf(f, "%hhu", & structure.seq); //if it does we fill the struct
n_read = fscanf(f, "%hhu", & structure.channel);
n_read = fscanf(f, "%hhu", & structure.num_samples);
num_samples_buffer[structure.channel - 1] = structure.num_samples;
for (int k = 0; k < structure.num_samples; k++) { //we fill the received channel's buffer with the data in bulk (if mode is single it's executed once)
switch (structure.channel) {
case 1:
curr_buff = buffer1;
break;
case 2:
curr_buff = buffer2;
break;
case 3:
curr_buff = buffer3;
break;
case 4:
curr_buff = buffer4;
break;
case 5:
curr_buff = buffer5;
break;
case 6:
curr_buff = buffer6;
break;
case 7:
curr_buff = buffer7;
break;
case 8:
curr_buff = buffer8;
break;
}
n_read = fscanf(f, "%hhu", & curr_buff[k]);
如果模式是连续的,我调用函数write_single,它将for循环后读取的值放入大小为8的临时缓冲区,每个通道一个位置;我用它为用户选择的每个通道保存一个样本,当我们感兴趣的每个通道都有样本时,我在输出文件中打印该行。
void write_single(FILE * ftxt, uint8_t sample, uint8_t channel) {
temp_buffer[structure.channel - 1] = sample;
counter++;
if (counter == num_channels) {
for (int k = 0; k < 8; k++) {
if (channel_buffer[k] != 0) {
printf("-%d-\n",k);
res = fprintf(ftxt, "%.1f", ((((float)((unsigned char) temp_buffer[k])) / 255) * 5));
if (res < 0) {
printf("error");
}
res = fprintf(ftxt, " ");
if (res < 0) {
printf("error");
}
}
}
res = fprintf(ftxt, "\n");
if (res < 0) {
printf("error");
}
counter = 0;
}
}
如果我们在批量模式下,并且我们收到了用户指定的所有通道的初始结构所指示的所有样本,我们调用函数write_bulk。它用于在用户选择的每个缓冲区上循环,并用于每个缓冲区的BUFFER_SIZE元素。
void write_bulk(void) {
for (int j = 0; j < BUFFER_SIZE; j++) {
for (int k = 0; k < 8; k++) {
if (channel_buffer[k] != 0) {
if (j >= num_samples_buffer[k]) {
break;
}
switch (k) {
case 0:
curr_buff_bulk = buffer1;
break;
case 1:
curr_buff_bulk = buffer2;
break;
case 2:
curr_buff_bulk = buffer3;
break;
case 3:
curr_buff_bulk = buffer4;
break;
case 4:
curr_buff_bulk = buffer5;
break;
case 5:
curr_buff_bulk = buffer6;
break;
case 6:
curr_buff_bulk = buffer7;
break;
case 7:
curr_buff_bulk = buffer8;
break;
}
res = fprintf(ftxt, "%.1f", ((((float)((unsigned char) curr_buff_bulk[j])) / 255) * 5));
res = fprintf(ftxt, " ");
}
}
res = fprintf(ftxt, "\n");
}
}
发送的值是头的int(在代码中称为key),其他每个数据的uint8_t。
我将串行设置为阻塞模式:
void serial_set_blocking(int fd, int should_block) {
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) {
printf ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
printf ("error %d setting term attributes", errno);
}
现在,它工作了一个短暂的时期,然后进入分段故障,我不能管理使用gdb(我是一个虚拟机,可能是原因?)因为它不打开串行如果我运行的代码与它,但我打印了一些值,并使用valgrind和问题看起来像有时它是非常容易出错,它需要的是一个值时,它应该读取通道,反之亦然,或者它读取通道时,它应该读取序列号,我失去了一些序列号..等我认为串行在阻塞模式将使它很容易,我读的关键,之后我读的价值观一个接一个,价值观应该是在秩序的权利?scanf和fprintf怎么样,可以使用它们吗?
编辑:我添加了缓冲区和结构的定义,即使它们将按照@克雷格埃斯蒂的建议进行修改
typedef struct bulk {
uint8_t seq;
uint8_t channel;
uint8_t num_samples;
}
bulk;
bulk structure;
uint8_t channel_buffer[8] = {0}; //used to keep track of what channel the user is interested in
uint8_t num_samples_buffer[8] = {0}; //used to limit the accesses to buffer on the number of samples we actually received
uint8_t num_channels = 0;
uint8_t buffer1[BUFFER_SIZE];
uint8_t buffer2[BUFFER_SIZE];
uint8_t buffer3[BUFFER_SIZE];
uint8_t buffer4[BUFFER_SIZE];
uint8_t buffer5[BUFFER_SIZE];
uint8_t buffer6[BUFFER_SIZE];
uint8_t buffer7[BUFFER_SIZE];
uint8_t buffer8[BUFFER_SIZE];
uint8_t temp_buffer[8] = {0}; //buffer to write the rows in continous mode
我从atmega 2560通过串行端口发送数据使用:http://mysinski.wieik.pk.edu.pl/MPUandMCU/Using%20printf%20with%20an%20AVR.pdf
这样使用它:
printf("%d\n", key); //32 bit
printf("%hhu\n", structure.seq); //8 bit
printf("%hhu\n", structure.channel); //8 bit
printf("%hhu\n", structure.num_samples); //8 bit
printf("%hhu\n", ADCH); //this is the sampled value, 8 bit
然后在我的客户端中,我在while(1)循环中读取键和结构体值:
while (1) {
int n_read = fscanf(f, "%d", & key); //we read 4 bytes and see if it equals the key
if (n_read < 0) {
perror("error");
}
if (key == 0x55aa) {
n_read = fscanf(f, "%hhu", & structure.seq); //if it does we fill the struct
if (n_read < 0) {
perror("error");
}
n_read = fscanf(f, "%hhu", & structure.channel);
if (n_read < 0) {
perror("error");
}
n_read = fscanf(f, "%hhu", & structure.num_samples);
if (n_read < 0) {
perror("error");
}
.
.
.
//other code
.
.
.
n_read = fscanf(f, "%hhu", & curr_buff[k]);
if (n_read < 0) {
printf("error");
}
.
.
.
//other code
.
.
.
}
key = 0; //we clear the key
}
}
下面是我在continous模式下得到的错误示例:
.
.
.
seq: 37
channel: 3
num_samp: 1
seq: 38
channel: 4
num_samp: 1
seq: 39
channel: 5
num_samp: 1
seq: 40
channel: 46 <-----------------error
num_samp: 5
1条答案
按热度按时间kkbh8khc1#
服务器中的printf函数将每个uint8_t转换为char值,所以如果我读取255,我将发送3个字节而不是1个字节,这最终会使波特率饱和。我按照@克雷格Estey的建议,将printf替换为低级别的UDR 0 =data来发送二进制值,并将fscanf替换为read。