您的位置 首页 产品

stm32完成printf重定向到LCD显示屏

嘿嘿,学习stm32已经有一段时间了。以前纠结过一个问题,(USART)串口的可变参数问题,查找C语言的书终于还是解决了,自己编写了一个USART…

嘿嘿,学习stm32现已有一段时间了。曾经纠结过一个问题,(USART)串口的可变参数问题,查找C言语的书总算仍是处理了,自己编写了一个USART_printf()函数,功用仿照C言语的printf,完成可变参数处理。有点小成就感。

我也因而宣布了一下C言语可变参数的博文, 同学们有爱好能够参阅一下:
http://blog.sina.com.cn/s/blog_6e22f4ce01010uud.html
最近几天在玩LCD显示屏,根本驱动写好了,并写了一个函数支撑中文英文混合打印,可是函数功用仍是不行强壮啊!串口的时分能够运用printf重定向,这么说开printf也能够重定向到LCD?
依据这个问题,自己昨日着手编写fputc()函数,意图是完成printf重定向到LCD。通过绵长的几个小时,调试成功了!!!调用printf(“hello,%s\n”, str)其间str内容是“world“;完成了在LCD上打印hello,world了。嘿嘿,后续的学习就便利很多了。
首要仍是相同先温习一下printf重定向到USART,原理是修正fputc()函数,将传递进来的参数转发到USART(串口),详细fputc()函数内容编写能够参阅以下比如:
int fputc(int ch, FILE* f)
{
if(ch == \n)
{
USART_SendData(USART1, \r);
USART_SendData(USART1, \n);
}
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}
看起来很熟悉吧。可是咱们现在是要把它重定向到LCD,怎样完成呢?
  相同的方法,把传递进来的参数转发到LCD就行了!嘿嘿,首要要有LCD驱动,也便是有LCD打印一个字符的函数(中文是两个字节),举一个比如。假定现已有一个打印一个字符的函数
LCD_Ascii_one();
函数参数先不睬,来到这一步就现已成功了一半了。像串口相同,只不过把
USART_SendData(USART1, (uint8_t)ch);
修正成
LCD_Ascii_One(…);//其间参数…中包括ch信息
这样, 整个结构就形成了, 下面是详细完成进程
先阐明一下我的LCD_Ascii_One函数:
LAC_Ascii_One(uint8_t X, uint16_t Y, uint8_t *Chinese, uint16_t Color);
四个参数的意义别离为:
uint8_t X 打印字符的横坐标
uint16_t Y 打印字符的纵坐标
uint8_t *Chinese 打印字符的字模首地址 //字模提取软件得到的, 字模放在sdcard, 运用时需求翻开文件
uint16_t Color 打印字符的色彩
获取字符的字模不是这儿的要点, 同学们另找材料.
string = Get_Ascii(a); //获取字符a的字模
调用LCD_Ascii_One(0, 10, string, WHITE);//打印
就完成了在LCD上的方位(0, 10)打印字符a, 色彩为白色
所以fputc函数里边会有这么一句
LCD_Ascii_One(x, y, ch, color);
不过仍是不行, 咱们需求打印一个字符后跳到下一个方位, 否则下次打印就覆盖了本次字符了
所以还有必要封装x, y, 让他们带有回忆功用, 呵呵,关键字static派上用场了
fputc函数需求声明
static uint16_t x = 0, y = 0;
为什么是uint16_t 应为我的LCD显示屏是240 * 320的
uint8_t 无法表明320, 所以是uint16_t, x也就趁便uint16_t了哈
调用玩LCD_Ascii_one之后
x += 8; //由于我提取字模是8 * 16的Ascii字模
还有一部是fputc需求的
return ch;
这样功用就完善一点了,加把劲, 持续换行功用
在调用LCD_Ascii_One()之前, 先判别x是否越界, 也便是当时这一行现已无法打印一个字符了
if(x > X_MAX – 8) //X_MAX是宏界说, 该值为240
{
x = 0; //x置零
y += 16; //y移至下一行
}
可是y也或许越界, 也便是说现已到了LCD的底部了, 我这儿处理是越界直接退出, 不打印字符了
if(y > Y_MAX – 16) //Y_MAX是宏界说, 该值是320
{
return ch; //直接退出
}
换行功用还有调用printf()时分的\n
所以仍是老样子, 跟串口相同:
if(ch == \n)
{
x = 0;
y += 16;
}
是否越界是上面的函数在判别.
来到这儿, 咱们从头再这儿一下fputc的内容
需求打印一个字符主动跳到下一个方位, x越界换行, y越界退出
当然这儿仅仅一个结构, 还有其他需求封装的, 例如中文, Ascii区别, 接下来会评论
仅仅fputc至少有必要包括句子:
int fputc(int ch, FILE* f)
{
static uint16_t x = 0, y = 0;
uint8_t string[16];
if(ch == \n) //换行
{
x = 0;
y += 16;
return ch;
}
if(x > X_MAX – 8) //X_MAX是宏界说, 该值为240
{
x = 0; //x置零
y += 16; //y移至下一行
}
if(y > Y_MAX – 16) //Y_MAX是宏界说, 该值是320
{
return ch; //直接退出
}
string = Get_Ascii(ch); //获取ch的字模
LCD_Ascii_One(x, y, string, color); //打印字符ch
x += 8; //跳转到下一个方位, 是否越界有上面函数判别
return ch;
}
(能够了解的同学接下来能够测验自己封装一下中英文了, 接下来咱们持续评论完成中英文混输.)
嘿嘿, 我的大约结构便是这样, 当然这样的功用仍是不行强壮的, 对, 咱们需求的是再强壮一点的printf, 接下来是, 完成中英文混输, 可变参数C言语现已帮咱们完成了, 也便是说咱们调用printf(“hello %s”, str);现已能打印出hello world而且换行了, 可是假如printf(“你好\n”);会怎样样? 乱码? 没错, 咱们现在仅仅完成了Ascii打印, 并没有中文, 这是与串口所不同的, 由于串口打印到电脑的超级终端, 超级终端现已帮咱们完成了这个功用了, 所以printf重定向到LCD还有再封装, 对, 要更强壮的函数, 完成完美的打印功用!!
中英文混输先要有一点准备常识.
1. 一个中文占两个字节, 一个Ascii占一个字节.
2. Ascii最高字节为0, 中文的两个字节最高字节都是1
上面的第二点再阐明一下
假如将Ascii当作是无符号数字, 它的数值小于128, 也便是0~127
假如将中文的两个字节别离当作无符号数字, 榜首个字节规模为128~255, 第二个字节也是128~255
嘿嘿, 判别中英文就有方法了~~~~
if(ch & 0x80) //判别最高位是否为1, 最高位为1表达式ch & 0x80为真
{
中文字节;
}
else
{
Ascii字节;
}
中文有两个字节, 所以要进入fputc两个才干打印出一个中文, 所以还有必要把先进来的ch保存起来, 等下一个字节进来在打印,当然Ascii假如进来就直接打印. 这样咱们又要有回忆功用的tmp[2]别离保存中文的两个字节了. 而且需求记载是计入的是榜首个中文字节仍是第二个中文字节
static uint8_t flag;
static uint8_t tmp[2];
当然, 要打印中文, 还有必要有一个打印中文的函数, 我这儿的函数是
LCD_Chinese_One(uint8_t X, uint16_t Y, uint8_t *Chinese, uint16_t Color);
uint8_t X 打印中文的横坐标
uint16_t Y 打印中文的纵坐标
uint8_t *Chinese 打印中文的字模
uint16_t Color 打印中文的色彩
string = Get_Chinese(“好”); //获取好的字模
例如调用LCD_Chinese_One(5, 20, string, WHITE); //打印
就在LCD的方位(5, 20)打印"好", 色彩为白色
来到这儿, 信任同学们都懂了吧, 烦琐一下, 咱们再来看看fputc应该怎样写
int fputc(int ch, FILE* f)
{
static uint16_t x = 0, y = 0; //坐标
uint8_t string[32]; //读取字模数组
static uint8_t flag = 0; //汉字榜首第二字节标志
static uint8_t tmp[2]; //保存汉字的两个字节
if(ch == \n) //换行
{
x = 0;
y += 16;
return ch;
}
if(ch & 0x80) //先判别是否为中文
{
if(flag == 0) //中文的榜首个字节仍是第二个字节
{
flag = 1; //接下来是第二个字节
tmp[0] = ch; //记载该字节
return ch; //依照C言语的fputc需求回来ch
}
else
{
flag = 0;
tmp[1] = ch;
if(x > X_MAX – 16) //判别是否越界
{
x = 0; //换行处理
y += 16; //字模巨细为16*16
}
if(y > Y_MAX – 16) //行越界
{
return ch; //直接退出处理
}
string = Get_Chinese(tmp);
LCD_Chinese_One(x, y, string, color);
x += 16;
return ch;
}
}
else
{
if(x > X_MAX – 8) //X_MAX是宏界说, 该值为240
{
x = 0; //x置零
y += 16; //y移至下一行
}
if(y > Y_MAX – 16) //Y_MAX是宏界说, 该值是320
{
return ch; //直接退出
}
string = Get_Ascii(ch); //获取ch的字模
LCD_Ascii_One(x, y, string, color); //打印字符ch
x += 8; //跳转到下一个方位, 是否越界有上面函数判别
return ch;
}
}
至此, 函数封装完成了.
测验调用一下
uint8_t str = “hello world”;
printf(“你好, 这是一个测验程序\n%s\n”, str);
在LCD上打印的是
你好, 这是一个测验程序
hello world
嘿嘿, 重定向成功了!!!
信任现已能满意广阔开发者的需求了, 有待完善的当地是控制符\t\r等, 不过都是适当简略的.
下面给出我的封装, 不过我是把字模放到sdcard的, 所以需求翻开文件, 读取文件等操作, 可是原理仍是相同的, 嘿嘿~~~~~~
#ifdef STDOUT_LCD
int fputc(int ch, FILE* f)
{
static uint32_t Offset, Read_Count;
static uint8_t Read_Font[32];
static FRESULT File_Status;
static FIL File;
static uint16_t x = 0, y = 0;
static uint8_t flag = 0;
static uint8_t tmp[2];
File_Status = f_open(&File, CHINESE_FONT, FA_OPEN_EXISTING | FA_READ); //中文字库
if(ch == \n) //换行处理
{
x = 0; //…
y += 18; //…
return ch;
}
if(ch & 0x80) //中文处理
{
if(flag == 0) //中文的两个字节判别, flag == 0 为榜首个字节
{
tmp[0] = (uint8_t)(ch); //把榜首个字节保存进来
flag = 1; //接下来是第二个字节
return ch; //依照C言语官方库, 回来ch
}
else//是中文的第二个字节
{
tmp[1] = (uint8_t)(ch); //保存该字节
flag = 0; //下一次是榜首个字节
if(x > X_MAX – 16) //判别是否需求换行
{
x = 0; //换行操作…
y += 18; //…
}
if(y > Y_MAX – 16) //判别是否越界
{
return ch; //越界退出
}
File_Status = f_open(&File, CHINESE_FONT, FA_OPEN_EXISTING | FA_READ);
if(Check_FileStatus(File_Status)) //判别文件操作状况
{
Offset = Chinese_Offset(tmp);//依据中文字库字模提取软件计算出汉字偏移方位
f_lseek(&File, Offset); //文件指针移至偏移方位
}
if(Check_FileStatus(File_Status)) //判别文件操作状况
{
File_Status = f_read(&File, Read_Font, 32, &Read_Count);
}
if(Check_FileStatus(File_Status)) //判别文件操作状况
{
LCD_Chinese_One(x, y, Read_Font, WHITE);//调用中文打印函数打印汉字
x += 16; //液晶横坐标+16, 中文为16*16的
}
File_Status = f_close(&File); //封闭文件
}
}
else
{
if(x > X_MAX – 8) //判别是否需求换行
{
x = 0; //换行操作…
y += 18; //…
}
if(y > Y_MAX – 16) //判别是否越界
{
return ch; //越界退出
}
File_Status = f_open(&File, ASCII_FONT, FA_OPEN_EXISTING | FA_READ);
if(Check_FileStatus(File_Status)) //判别文件操作状况
{
Offset = ((uint8_t)(ch) – 0x20) << 4; //计算出Ascii偏移地址, 要先越过Ascii控制字符
f_lseek(&File, Offset); //文件指针移至偏移方位
}
if(Check_FileStatus(File_Status))//判别文件操作状况
{
f_read(&File, Read_Font, 16, &Read_Count);//读取字模信息
}
if(Check_FileStatus(File_Status))//判别文件操作状况
{
LCD_Ascii_One(x, y, Read_Font, WHITE); //调用Ascii打印函数打印字符
x += 8;//Ascii像素为8*16, 横坐标+8
}
File_Status = f_close(&File); //封闭文件
}
return ch;
}
#endif //#ifdef STDOUT_LCD

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/chanpin/275000.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部