Printf输出问题,这是一个困扰我很久的问题,因为从接触单片机开始,我就对这个功能有近乎执着的使用,每次都会出问题,但是又不知道问题在哪里。需要用到的是通用同步异步收发器(USART),他的作用是通信,他的作用就是通信和中断以及其他的功能,本人暂时还没涉及这么深,使用它就需要就将它加载到启动文件之中,另外还需要加上GPIO和NVIC的启动文件。
第一步,需要在自己创建的.C文件中写一个初始化函数,用来初始化usart、gpio和NVIC。GPIO的初始化只需要将对应的引脚初始化一下,比如引脚模式、引脚、速度。Tx引脚(信号发送的)模式使用复用推挽输出(GPIO_Mode_AF_PP),一般串口输出都用这个模式,Rx引脚(接收信号)则用输入浮空(GPIO_Mode_IN_FLOATING),之后做USART的初始化配置,首先第一个波特率,他决定了信号的传输速度,这里需要特别提一下,如果波特率设置的不对的话会导致乱码,甚至无法传输信号的,所以对于刚学习的人,可以将波特率设置的低一些,这里我设置的是9600,之后只需要按部就班的配置字长,停止位,奇偶失能,硬件流控制使能以及发送接收使能,初始化USART_Init以及使能USART1;再之后配置NVIC即可,NVIC的官方说法是嵌套向量中断控制器,但是目前的我感觉他就是一个决定让谁先去上厕所的所长,比如说有4个人去上厕所,但是蹲坑只有一个,他就会把这些人分组,然后排序,比如把他们分到同一个组,按A/B/C/D依次去上测试,或者把人分成两个组,让甲组的人先去,乙组的人后去,甲组中,又让A先去,B后去,这样排队上厕所。当然还可以细分哈,只是这样一个描述,我在这里配置的话就是将我这个串口中断的优先级组别放在了NVIC_PriorityGroup_2之中,排名老三,然后先占优先级为1,从优先级为2,这里可以自由设置,但是数值是限制的,总之数值越小,优先级越高,注意配置完之后使用INIT函数做初始化处理。
第二步,编写printf重定向函数,首先定义函数写上防止进入半主机工作模式的函数,拿上直接用即可,代码如下:
#pragma import(__use_no_semihosting)
void sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
};FILE __stdout;
然后是fputc重定向(int fputc(int ch,FILE *p) ),将USART的数据寄存器DR中的值赋值给我们的形参ch,在之后做一个while判断发送数据寄存器空标志位(USART_FLAG_TXE)是否为0就可以了,如果为0,则表示没有数据再发送过来了,返回ch。这样printf重定向就完成了。对了,记得勾选设置里面Target的Use MicroLIB和C/C++中的C99 Mode使用C语言库。
代码如下:
int fputc(int ch,FILE *p)
{
/* ch = USART1->DR */
USART_SendData(USART1,(u8)ch);
/* 判断是否还有数据发过来 */
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
/* 返回USART1收到的数据 */
return ch;
}
第三步,上诉步骤完成之后,在主函数里面使用Printf函数打印即可。
这里还有一种快捷打印的方法,使用DMA接收和打印,使用DMA进行发送和接收是不占用CPU的,所以在打印的同时,CPU还可以干其他的事情,这就提供了一个高效处理数据的环境。是通过设置USART_CR3寄存器的DMAR位激活使用DMA进行接收,每次接收到一个字节DMA控制器就就把数据从USART_DR寄存器传送到指定的SRAM区这个后面彻底熟悉之后再做学习笔记。可以看STM32的参考手册25.3.13章节,利用DMA连续通讯。