Proteus 中的数组使用 WinAVR C 大小问题
Array in Proteus using WinAVR C size issue
我有一个实验室作业需要我使用 Atmega328P 做一个 ADC,并使用 USART 将数字值传输到 MILFORD-4X20-BKP LCD 显示器。 LCD需要在第一行显示2字节格式(十进制,0-255)的值,第三行显示字格式(4字节,0-1023)。
我成功地做到了这一点,但是因为我不确定数组的大小,所以我最初让它们都足够大而没有问题。当我将其更改为我认为必要的内容时,我遇到了一个奇怪的错误。这是下面显示的奇怪符号(或者我猜在底部)。该位置的符号将取决于电位器值。
所以这是我的想法。
我为发送到 LCD 的 buff 分配了 36 个(位置 0 为 +1)位置。我为单词值分配了 3 给 buff2(4 n 个位置)
最后 4 用于 buff1 的 2 字节值(5 n 个位置)
buff[36]; buff1[4]; buff2[3];
单词值的 3n 个位置有效,但是当我为 2 字节值放置 4n 时,错误出现了。见第一张图
根据buff和buff1的不同数组值,该bug还表现为第3行末尾出现0-255值的一部分。第二张照片有
buff[37], buff1[2], buff2[3]
最后请注意,如果我将值更改为 buff1[5]
,错误就会消失。但是为什么呢? 2 字节的数组大小应小于 4 字节的数组大小。
我正在尽力解释我的问题,但不知道我是否足够清楚。我知道我正在让我的数组交叉到彼此的内存地址,但我不知道如何以及在何处。
/*
* Serial Lcd.c
*
* Use's a 4x20 serial LCD display.
*
* Adapted by Phil J to suit Atmega328P: 15/2/2015 (corrected Usart_Rx Int Vector address ref. for 328)
*
* Editted by Tomi Fodor
*
*/
#define F_CPU 16000000UL
#define BAUDRATE 9600 - change to External 16MHz crystal on MCU
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "stdlib.h"
#include "USART.h"
// Global Variables
// Note the use of the volatile keyword to ensure that the compiler knows that these variables can be changed at
// any time, including by the ISR
volatile int i=0;
volatile uint16_t buffer[]; // 20 place array
volatile char buff[36]; // var sent out value
volatile char buff1[4]; // var for the pot value / 4 ***** HAS TO BE AT LEAST 4 FOR SOME REASON (5 w/o bug), SHOULD BE FINE AT 2
volatile char buff2[3]; // var for the actual pot value
volatile uint16_t StrRxFlag=0;
volatile int Ana, Bell; // pot value
int main(void)
{
buff[4]=' ';buff[5]='P';buff[6]='o';buff[7]='t';buff[8]=' ';buff[9]='V';buff[10]='a';buff[11]='l';buff[12]='(';buff[13]='D';buff[14]=')'; // constants to be displayed
_delay_ms(500);
ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1); // Enables the ADC, sets the ADC to use the division factor 64 for the ADC clock
USART_interrupt_init();
USART_putstring("Ready "); // Send String to the LCD
// USART_putstring(buff3);
USART_send('\r'); // Send carriage return
// USART_send('\n'); // Send linefeed
_delay_ms(500); // Allows for the LCD module to initialize
while(1)
{
USART_send(254); // LCD control mode
USART_send(0); // LCD HOME command
USART_send(254);
USART_send(1); // LCD CLEAR SCREEN
buff[0] = ' '; // Required for offset of display
buff[4] = ' '; // Signifies terminator of pot
ADCSRA |= (1<<ADSC); // Starts A-D conversion
while (ADCSRA & (1<<ADSC)); // Wait till A-D conversion is complete
Ana = ADCW/4; // Get A-D result
Bell = ADCW; // Get actual A-D result
itoa(Ana,buff1,10); // Creats the dec value of the Analogue value [stdlib.h]
itoa(Bell,buff2,10); // actual
if (buff1[1] == '[=11=]') // If only 1 digit
{
buff[1] = ' '; // Not hundreds
buff[2] = ' '; // Not tens
buff[3] = buff1[0]; // Place in single digit
}
else if(buff1[2] == '[=11=]') // If only 2 digits
{
buff[1] = ' '; // Not hundreds
buff[2] = buff1[0]; // Shift
buff[3] = buff1[1]; // Shift
}
else
{
buff[1] = buff1[0]; // Shift
buff[2] = buff1[1]; // Shift
buff[3] = buff1[2]; // Shift
}
for(i=0;i<25;i++)
{
buff[i+15] = ' ';
}
buff[25]=' ';buff[26]='P';buff[27]='o';buff[28]='t';buff[29]=' ';buff[31]='V';buff[32]='a';buff[33]='l';buff[34]='(';buff[35]='D';buff[36]=')'; // constants to be displayed
if (buff2[1] == '[=11=]') // If only 1 digit
{
buff[21] = ' '; // Not thousands
buff[22] = ' '; // Not hundreds
buff[23] = ' '; // Not tens
buff[24] = buff2[0]; // Place in single digit
}
else if(buff2[2] == '[=11=]') // If only 2 digits
{
buff[21] = ' '; // Not thousands
buff[22] = ' '; // Not hundreds
buff[23] = buff2[0]; // Shift
buff[24] = buff2[1]; // Shift
}
else if(buff2[3] == '[=11=]') // If only 3 digits
{
buff[21] = ' '; // Not thousands
buff[22] = buff2[0]; // Shift
buff[23] = buff2[1]; // Shift
buff[24] = buff2[2]; // Shift
}
else
{
buff[21] = buff2[0]; // Shift
buff[22] = buff2[1]; // Shift
buff[23] = buff2[2]; // Shift
buff[24] = buff2[3]; // Shift
}
USART_putstring(buff);
USART_send('\r');
_delay_ms(500);
}
}
//ISR(USART0_RX_vect) - not for 328
ISR(USART_RX_vect) //this is the right vector ref, not above
{
buffer[i]=UDR0; //Read USART data register
if(buffer[i++]=='\r') //check for carriage return terminator and increment buffer index
{
// if terminator detected
StrRxFlag=1; //Set String received flag
buffer[i-1]=0x00; //Set string terminator to 0x00
i=0; //Reset buffer index
}
}
您提到的问题可能是由于使用调用 USART_putstring(buff);
时的非空终止字符串引起的。 C 字符串 by definition 要求最后一个字符为 [=19=]
( NULL )。示例:
给定 char string[5];
|h|e|r|e|[=21=]|
合法
|h|e|r|e|s| |a| |b|u|g|
是填充缓冲区,但不是字符串
在您的示例中有些地方您正在将非 NULL 字符写入缓冲区的最后一个元素。例如 buff
被创建为一个包含 36 个元素的数组:
volatile char buff[36]; // var sent out value
行中:
buff[25]=' ';buff[26]='P';buff[27]='o';buff[28]='t';buff[29]=' ';buff[31]='V';buff[32]='a';buff[33]='l';buff[34]='(';buff[35]='D';buff[36]=')'; // constants to be displayed
index 35(最后一个合法索引)填充了 D
字符。索引 36(不合法)填充了 )
,并且至少会导致 运行 次错误。那么根据定义,因为它不是 NULL 终止的,所以它不是字符串,将它用作一个字符串将导致 Undefined Behavior。
在这里,buf2 也是用 3 个元素创建的:
volatile char buff2[3]; // var for the actual pot value
但是这一行,使用了索引3:(只有0-2有效)
else
{
buff[21] = buff2[0]; // Shift
buff[22] = buff2[1]; // Shift
buff[23] = buff2[2]; // Shift
buff[24] = buff2[3]; // Shift <<< only buff2[0] - buff2[2] are legal
}
这些错误将编译,但会在 运行 时导致指针越界。
这个变量有一个未定义的大小,应该标记一个错误:
volatile uint16_t buffer[]; // 20 place array
假设您希望它成为:
volatile uint16_t buffer[20]; // 20 place array
以后你在这里用:
ISR(USART_RX_vect) //this is the right vector ref, not above
{
buffer[i]=UDR0;
因为我不确定您正在使用什么 C 标准(即,如果它不是 ANSI C),我不知道您的环境是否会在编译时为 int 数组标记未定义的大小。但是由于定义了其余的数组大小,所以这个看起来很可疑。
此外,我看到您将我定义为:
volatile int i=0;
i
的边界是众所周知的吗?我有可能超越价值 19 吗? (假设数组在某个时候被初始化)
我有一个实验室作业需要我使用 Atmega328P 做一个 ADC,并使用 USART 将数字值传输到 MILFORD-4X20-BKP LCD 显示器。 LCD需要在第一行显示2字节格式(十进制,0-255)的值,第三行显示字格式(4字节,0-1023)。
我成功地做到了这一点,但是因为我不确定数组的大小,所以我最初让它们都足够大而没有问题。当我将其更改为我认为必要的内容时,我遇到了一个奇怪的错误。这是下面显示的奇怪符号(或者我猜在底部)。该位置的符号将取决于电位器值。
所以这是我的想法。 我为发送到 LCD 的 buff 分配了 36 个(位置 0 为 +1)位置。我为单词值分配了 3 给 buff2(4 n 个位置) 最后 4 用于 buff1 的 2 字节值(5 n 个位置)
buff[36]; buff1[4]; buff2[3];
单词值的 3n 个位置有效,但是当我为 2 字节值放置 4n 时,错误出现了。见第一张图
根据buff和buff1的不同数组值,该bug还表现为第3行末尾出现0-255值的一部分。第二张照片有
buff[37], buff1[2], buff2[3]
最后请注意,如果我将值更改为 buff1[5]
,错误就会消失。但是为什么呢? 2 字节的数组大小应小于 4 字节的数组大小。
我正在尽力解释我的问题,但不知道我是否足够清楚。我知道我正在让我的数组交叉到彼此的内存地址,但我不知道如何以及在何处。
/*
* Serial Lcd.c
*
* Use's a 4x20 serial LCD display.
*
* Adapted by Phil J to suit Atmega328P: 15/2/2015 (corrected Usart_Rx Int Vector address ref. for 328)
*
* Editted by Tomi Fodor
*
*/
#define F_CPU 16000000UL
#define BAUDRATE 9600 - change to External 16MHz crystal on MCU
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "stdlib.h"
#include "USART.h"
// Global Variables
// Note the use of the volatile keyword to ensure that the compiler knows that these variables can be changed at
// any time, including by the ISR
volatile int i=0;
volatile uint16_t buffer[]; // 20 place array
volatile char buff[36]; // var sent out value
volatile char buff1[4]; // var for the pot value / 4 ***** HAS TO BE AT LEAST 4 FOR SOME REASON (5 w/o bug), SHOULD BE FINE AT 2
volatile char buff2[3]; // var for the actual pot value
volatile uint16_t StrRxFlag=0;
volatile int Ana, Bell; // pot value
int main(void)
{
buff[4]=' ';buff[5]='P';buff[6]='o';buff[7]='t';buff[8]=' ';buff[9]='V';buff[10]='a';buff[11]='l';buff[12]='(';buff[13]='D';buff[14]=')'; // constants to be displayed
_delay_ms(500);
ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1); // Enables the ADC, sets the ADC to use the division factor 64 for the ADC clock
USART_interrupt_init();
USART_putstring("Ready "); // Send String to the LCD
// USART_putstring(buff3);
USART_send('\r'); // Send carriage return
// USART_send('\n'); // Send linefeed
_delay_ms(500); // Allows for the LCD module to initialize
while(1)
{
USART_send(254); // LCD control mode
USART_send(0); // LCD HOME command
USART_send(254);
USART_send(1); // LCD CLEAR SCREEN
buff[0] = ' '; // Required for offset of display
buff[4] = ' '; // Signifies terminator of pot
ADCSRA |= (1<<ADSC); // Starts A-D conversion
while (ADCSRA & (1<<ADSC)); // Wait till A-D conversion is complete
Ana = ADCW/4; // Get A-D result
Bell = ADCW; // Get actual A-D result
itoa(Ana,buff1,10); // Creats the dec value of the Analogue value [stdlib.h]
itoa(Bell,buff2,10); // actual
if (buff1[1] == '[=11=]') // If only 1 digit
{
buff[1] = ' '; // Not hundreds
buff[2] = ' '; // Not tens
buff[3] = buff1[0]; // Place in single digit
}
else if(buff1[2] == '[=11=]') // If only 2 digits
{
buff[1] = ' '; // Not hundreds
buff[2] = buff1[0]; // Shift
buff[3] = buff1[1]; // Shift
}
else
{
buff[1] = buff1[0]; // Shift
buff[2] = buff1[1]; // Shift
buff[3] = buff1[2]; // Shift
}
for(i=0;i<25;i++)
{
buff[i+15] = ' ';
}
buff[25]=' ';buff[26]='P';buff[27]='o';buff[28]='t';buff[29]=' ';buff[31]='V';buff[32]='a';buff[33]='l';buff[34]='(';buff[35]='D';buff[36]=')'; // constants to be displayed
if (buff2[1] == '[=11=]') // If only 1 digit
{
buff[21] = ' '; // Not thousands
buff[22] = ' '; // Not hundreds
buff[23] = ' '; // Not tens
buff[24] = buff2[0]; // Place in single digit
}
else if(buff2[2] == '[=11=]') // If only 2 digits
{
buff[21] = ' '; // Not thousands
buff[22] = ' '; // Not hundreds
buff[23] = buff2[0]; // Shift
buff[24] = buff2[1]; // Shift
}
else if(buff2[3] == '[=11=]') // If only 3 digits
{
buff[21] = ' '; // Not thousands
buff[22] = buff2[0]; // Shift
buff[23] = buff2[1]; // Shift
buff[24] = buff2[2]; // Shift
}
else
{
buff[21] = buff2[0]; // Shift
buff[22] = buff2[1]; // Shift
buff[23] = buff2[2]; // Shift
buff[24] = buff2[3]; // Shift
}
USART_putstring(buff);
USART_send('\r');
_delay_ms(500);
}
}
//ISR(USART0_RX_vect) - not for 328
ISR(USART_RX_vect) //this is the right vector ref, not above
{
buffer[i]=UDR0; //Read USART data register
if(buffer[i++]=='\r') //check for carriage return terminator and increment buffer index
{
// if terminator detected
StrRxFlag=1; //Set String received flag
buffer[i-1]=0x00; //Set string terminator to 0x00
i=0; //Reset buffer index
}
}
您提到的问题可能是由于使用调用 USART_putstring(buff);
时的非空终止字符串引起的。 C 字符串 by definition 要求最后一个字符为 [=19=]
( NULL )。示例:
给定 char string[5];
|h|e|r|e|[=21=]|
合法
|h|e|r|e|s| |a| |b|u|g|
是填充缓冲区,但不是字符串
在您的示例中有些地方您正在将非 NULL 字符写入缓冲区的最后一个元素。例如 buff
被创建为一个包含 36 个元素的数组:
volatile char buff[36]; // var sent out value
行中:
buff[25]=' ';buff[26]='P';buff[27]='o';buff[28]='t';buff[29]=' ';buff[31]='V';buff[32]='a';buff[33]='l';buff[34]='(';buff[35]='D';buff[36]=')'; // constants to be displayed
index 35(最后一个合法索引)填充了 D
字符。索引 36(不合法)填充了 )
,并且至少会导致 运行 次错误。那么根据定义,因为它不是 NULL 终止的,所以它不是字符串,将它用作一个字符串将导致 Undefined Behavior。
在这里,buf2 也是用 3 个元素创建的:
volatile char buff2[3]; // var for the actual pot value
但是这一行,使用了索引3:(只有0-2有效)
else
{
buff[21] = buff2[0]; // Shift
buff[22] = buff2[1]; // Shift
buff[23] = buff2[2]; // Shift
buff[24] = buff2[3]; // Shift <<< only buff2[0] - buff2[2] are legal
}
这些错误将编译,但会在 运行 时导致指针越界。
这个变量有一个未定义的大小,应该标记一个错误:
volatile uint16_t buffer[]; // 20 place array
假设您希望它成为:
volatile uint16_t buffer[20]; // 20 place array
以后你在这里用:
ISR(USART_RX_vect) //this is the right vector ref, not above
{
buffer[i]=UDR0;
因为我不确定您正在使用什么 C 标准(即,如果它不是 ANSI C),我不知道您的环境是否会在编译时为 int 数组标记未定义的大小。但是由于定义了其余的数组大小,所以这个看起来很可疑。
此外,我看到您将我定义为:
volatile int i=0;
i
的边界是众所周知的吗?我有可能超越价值 19 吗? (假设数组在某个时候被初始化)