2、显示数字方式的修改
lcd示例代码中有个 void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);
这个函数可以以指定宽度显示一个数字,并通过参数确定是否补前导0,以及是否在显示时,不擦除背景以实现叠加输出的效果。
我在尝试将代表时间的总秒数输出并右对齐时,发现,这个函数有个问题。从 1970年算起,到今天经过的总秒数已经是 10 位数了。我设置的宽度是12,但是显示的值确很诡异。
大家可以试试用这个函数显示 1234567890,12位宽。实际显示的是 101234567890。
经过研究,发现,实际上是这个函数内部判断数字位数的方法有问题。判断时使用了 10 的 n 次方,n 的初始值随总宽度的增加而增加,但是当 n 达到一定值时,计算的结果会超过 u32 上限,导致溢出折回从最小值开始重新计数,结果就导致错误。
我的想法是,干脆用非标准库中 itoa 的类似方法将数字转换成对应的字符串,之后再根据需要直接补零。
代码中很多名称都变了,不过应该不影响大家去对照看。另外,颜色我定义了一个透明色用于实现叠加显示的效果。
同时,将背景色和前景色作为参数传递给相应方法。(不使用全局变量了,因为会造成多任务时,画面颜色冲突问题)
[mw_shl_code=c,true]// 将数字按指定基数转换成字符串。
char _Index[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char* fun_NumberToString(long aNumber, char *aString, u8 aRadix)
{
unsigned long lNumber;
int i = 0, j, k;
if(aRadix == 10 && aNumber < 0)
{
aString[i++] = '-';
lNumber = (unsigned long)-aNumber;
}
else
lNumber = (unsigned long)aNumber;
do
{
aString[i++] = _Index[lNumber % aRadix];
lNumber /= aRadix;
} while(lNumber);
aString = '\0';
if(aString[0] == '-')
k = 1;
else
k = 0;
for(j = k; j <= (i - 1) / 2; j++)
{
char temp = aString[j];
aString[j] = aString[i - 1 + k - j];
aString[i - 1 + k - j] = temp;
}
return aString;
}[/mw_shl_code]
[mw_shl_code=c,true]void LCD_DrawNum(FontSizeTypeDef aSize, u32 aNumber, u16 aX, u16 aY, u8 aLength, bool aPadZero, ColorTypeDef aBackColor, ColorTypeDef aForeColor)
{
u8 lIndex, i;
u8 lLength;
char lNumberString[65];
fun_NumberToString(aNumber, lNumberString, 10);
lLength = strlen(lNumberString);
if(aLength < lLength)
aLength = lLength;
for(lIndex = 0; lIndex < aLength - lLength; lIndex++)
LCD_DrawChar(aSize, (aPadZero == TRUE ? '0' : ' '), aX + (aSize / 2) * lIndex, aY, aBackColor, aForeColor);
for(i = 0; i < lLength; i++)
LCD_DrawChar(aSize, lNumberString, aX + (aSize / 2) * (lIndex + i), aY, aBackColor, aForeColor);
}[/mw_shl_code]
[mw_shl_code=c,true]//上述代码中涉及到两个类型,是我定义的两个枚举类型。其中颜色取值参考了原子示例代码
typedef enum
{
FONTSIZE_16 = 16,
FONTSIZE_24 = 24,
FONTSIZE_32 = 32
} FontSizeTypeDef;
typedef enum {
COLOR_TRANSPARENT = 0x0001,// 透明色,背景色选择此颜色,可实现叠加显示效果。需要对应方法以此作为判断
COLOR_WHITE = 0xFFFF,
COLOR_BLACK = 0x0000,
COLOR_BLUE = 0x001F,
COLOR_BRED = 0xF81F,
COLOR_GRED = 0xFFE0,
COLOR_GBLUE = 0x07FF,
COLOR_RED = 0xF800,
COLOR_MAGENTA = 0xF81F,
COLOR_GREEN = 0x07E0,
COLOR_CYAN = 0x7FFF,
COLOR_YELLOW = 0xFFE0,
COLOR_BROWN = 0xBC40, // 棕色
COLOR_BRRED = 0xFC07, // 棕红色
COLOR_GRAY = 0x8430, // 灰色
COLOR_DARKBLUE = 0x01CF, // 深蓝色
COLOR_LIGHTBLUE = 0x7D7C, // 浅蓝色
COLOR_GRAYBLUE = 0x5458, // 灰蓝色
COLOR_LIGHTGREEN = 0x841F, // 浅绿色
COLOR_LIGHTGRAY = 0xEF5B, // 浅灰色(PANNEL)
COLOR_LGRAY = 0xC618, // 浅灰色(PANNEL),窗体背景色
COLOR_LGRAYBLUE = 0xA651, // 浅灰蓝色(中间层颜色)
COLOR_LBBLUE = 0x2B12 // 浅棕蓝色(选择条目的反色)
} ColorTypeDef;
[/mw_shl_code]
涉及到的实现透明色的 LCD_DrawChar 方法,也是改造自原子的示例代码
[mw_shl_code=c,true]void LCD_DrawChar(FontSizeTypeDef aSize, u8 aChar, u16 aX, u16 aY, ColorTypeDef aBackColor, ColorTypeDef aForeColor)
{
u8 lByteValue, lByteIndex, lBitIndex;
u8 lByteCount = (aSize / 8) * (aSize / 2); // 得到字体一个字符对应点阵集所占的字节数
u8 lCharIndex = aChar - ' '; // 得到偏移后的值(ASCII字库是从空格开始取模,所以 - ' '就是对应字符的字库)
u16 x0 = aX;
u16 y0 = aY;
for(lByteIndex = 0; lByteIndex < lByteCount; lByteIndex++)
{
aX = x0 + lByteIndex / (aSize / 8);
aY = lByteIndex % (aSize / 8) == 0 ? y0 : aY;
if(aSize == FONTSIZE_16)
lByteValue = ASCII16[lCharIndex][lByteIndex]; // 调用1608字体
else if(aSize == FONTSIZE_24)
lByteValue = ASCII24[lCharIndex][lByteIndex]; // 调用2412字体
else if(aSize == FONTSIZE_32)
lByteValue = ASCII32[lCharIndex][lByteIndex]; // 调用3216字体
else
return; // 没有的字库
// 从上到下,从左到右,按列的点阵。
for(lBitIndex = 0; lBitIndex < 8; lBitIndex++)
{
if(aX >= gLCDDevice.Width || aY >= gLCDDevice.Height)
return; //超区域了
if(lByteValue & 0x80)
LCD_DrawPointFast(aX, aY, aForeColor);
else if(aBackColor != COLOR_TRANSPARENT)
LCD_DrawPointFast(aX, aY, aBackColor);
lByteValue <<= 1;
aY++;
}
}
}[/mw_shl_code]
|