效果
- keil5工程设置,这一步很重要:
- 在任意的源文件里重写
int fputc(int ch, FILE* f)
函数
代码:
print.h
#ifndef __PRINT_H__
#define __PRINT_H__
#include "stm32f10x.h"
#include "stdio.h"
/* 打印输出到那里 */
#define PUT_USART 0x01 // 串口输出
#define PUT_LCD1_44 0x02 // 输出到Lcd1.44屏幕
#define IS_PUT_VALUE(V) (V == PUT_USART || V == PUT_LCD1_44)
/* 重定向方向 */
extern uint8_t PRINT_FOR;
#define SET_PRINT_FOR(__T) PRINT_FOR = IS_PUT_VALUE(__T) ? __T : PUT_USART
/* 使用Lcd输出时的参数 */
typedef struct
{
uint8_t x; // 坐标x
uint8_t y; // 坐标y
uint16_t Back_color; // 背景颜色
uint16_t Point_color; // 字体颜色
uint8_t mode; // 叠加选择
} Lcd_Put_value;
void fputc_lcd_value(uint8_t x, uint8_t y, uint16_t fontColor, uint16_t breakColor, uint8_t mode);
int fputc(int ch, FILE *f);
#endif
print.c
#include "print.h"
#include "LCD1_44.h"
/* printf重定向到哪里 */
uint8_t PRINT_FOR = PUT_USART; // 默认串口
/* Lcd屏参数值 */
Lcd_Put_value Lcd_fValue = {0x00, 0x00, 0x0000, 0xFFFF, 0};
/* Lcd屏设置参数时是否正确,不正确则不会输出 */
uint8_t Lcd_value_corr = 1;
/**
* @brief 设置重定向后输出到Lcd屏的各种参数
* **/
void fputc_lcd_value(uint8_t x, uint8_t y, uint16_t fontColor, uint16_t breakColor, uint8_t mode) {
if (Lcd_assert_param(x, y)) {
Lcd_value_corr = 0;
return;
}
else Lcd_value_corr = 1;
Lcd_fValue.x = x;
Lcd_fValue.y = y;
Lcd_fValue.Back_color = breakColor;
Lcd_fValue.Point_color = fontColor;
Lcd_fValue.mode = mode;
}
/**
* @brief 重定向printf函数
* **/
int fputc(int xch, FILE *f) {
/* 因为这个中文字符占2个字节所以要记录是否为第二个字节 */
static uint8_t firstChinese[2] = {0x00, 0x00};
uint8_t ch = (uint8_t)xch;
/* 串口打印 */
if (PRINT_FOR == PUT_USART) {
USART_SendData(USART1, (char)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
/* 输出到Lcd1.44屏幕 */
else {
if (!Lcd_value_corr) { // 参数设置错误
return xch;
}
if (Lcd_fValue.y+16 > LCD_Y_MAX_PIXEL) {
Lcd_value_corr = 0;
return xch;
}
// 判断是否为中文
if (ch > 0x80) {
if (Lcd_fValue.x+16 > LCD_X_MAX_PIXEL) {
Lcd_fValue.y += 16;
if (Lcd_fValue.y >= LCD_Y_MAX_PIXEL) {
Lcd_value_corr = 0;
return xch;
}
Lcd_fValue.x = 0;
}
// 如果是第一个字节
if (!firstChinese[0]) {
firstChinese[0] = ch;
return xch;
}
firstChinese[1] = ch;
Lcd_DrawFont16(Lcd_fValue.x, Lcd_fValue.y, firstChinese, Lcd_fValue.Point_color, Lcd_fValue.Back_color, Lcd_fValue.mode);
firstChinese[0] = 0x00;
Lcd_fValue.x += 16;
}
else {
if(ch == 0x0A) { // 换行符号
Lcd_fValue.x = 0;
Lcd_fValue.y += 16;
if (Lcd_fValue.y >= LCD_Y_MAX_PIXEL) {
Lcd_value_corr = 0;
}
return xch;
}
if (Lcd_fValue.x+8 > LCD_X_MAX_PIXEL) {
Lcd_fValue.y += 16;
if (Lcd_fValue.y >= LCD_Y_MAX_PIXEL) {
Lcd_value_corr = 0;
return xch;
}
Lcd_fValue.x = 0;
}
Lcd_Putchar(Lcd_fValue.x, Lcd_fValue.y, ch, Lcd_fValue.Point_color, Lcd_fValue.Back_color, Lcd_fValue.mode);
Lcd_fValue.x += 8;
}
}
return xch;
}
main.c
#include "delay.h"
#include "LCD1_44.h"
#include "stm32f10x.h"
#include "font.h"
#include "tim.h"
#include "usart.h"
#include "stdio.h"
#include "GUI.h"
#include "DS18B20.h"
#include "print.h"
/**
* @brief 板载LED,使用的管脚为PC13
* 低电平LED亮
* **/
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // 点亮
}
int main(void)
{
uint8_t i;
delay_init();
LED_Init();
TIM2_Init(200-1, 360-1); // ((arr+1)/72000000)*(psc+1) = (200/72000000)*360 = 1ms
Usart_Init(115200);
Lcd_Init();
Lcd_Clear(0x0000);
// 设置屏幕方向
Lcd_SetDisplayDirection(LCD_REVERSALVERTICAL);
Lcd_Print(1, 17, "023456789)(<{}>ABC中#文啊DEF%$试&GHjkl.mnopq^*MZyakg&@d;..测", WHITE, BLACK, 1);
for (i=0; i < 2; i++) delay_ms(1000);
Lcd_Clear(0x0000);
// 设置printf重定向方向
SET_PRINT_FOR(PUT_LCD1_44);
fputc_lcd_value(0, 20, WHITE, BLACK, 0);
printf("当Apsod&前*Hnldskd09wjr温度\nfds中)");
for (i=0; i < 4; i++) delay_ms(1000);
while (1)
{
fputc_lcd_value(0, 20, WHITE, BLACK, 0);
printf("当前温度:%.3f", ReadTemperature());
for (i=0; i < 5; i++)
delay_ms(1000);
}
}
最后,printf
是真滴香。