简介:
在实际的开发中,我们对于uart的转串口使用往往是通过对stdio库中的fputc等函数进行重定向来进行实现,实现方法如下图:
我们的目的是高级和低级函数都不target-dependent,并使用系统I/O功能与硬件接口。然而,高级库函数通过调用低级函数来执行输入/输出,而这些低级函数又调用target-dependent的系统I/O功能。 对于这样的问题,有这些解决方案:
- 避免使用高级库函数。
- 重新定义低级库函数。
- 重新定义系统 I/O 功能。
对于重新定义低级库函数或系统I/O函数哪个是更好的解决方案,这取决于你的使用场景。例如,UART一次写入一个字符时,默认使用缓冲,所以重新定义一个没有缓冲的函数可能更适合UART。然而,在需要进行缓冲操作的地方,重新定义系统I/O函数可能会更合适。
ARM编译器运行时,MicroLib通过低级函数来与硬件进行接口。它实现了一组简化的高级函数,因此不实现系统I/O函数。因此,在使用MicroLib的情况下,不能重新定义系统I/O函数。
为了解决这个问题,可以使用 ARM 编译器的 I/O 重定向的方法来实现在使用MicroLib的情况下,进行重定义系统I/O函数。
实验平台为自制stm32f103c8t6开发板,理论上可应用于所有ARM架构芯片。
实验操作:
1.打开keil软件,这里使用的版本是keil uVision V5.38.0.0版本,新建工程,选择f103c8,进入Manage Run-Time Environment页面
2.选择运行资源,如下图:
3.点击确定进入工程,此时工程文件如图:
点击进入RTE_Device.h文件,点击编辑栏下方 后进入配置,打开USART1,开启RX和TX引脚。
4.向源文件目录添加文件:
在User Code Template中选择STDIN和STDOUT,添加stdin_USART.c与stdout_USART.c文件。
与修改RTE_Device.h相同,进入配置界面,将两个文件配置均设置为USART1与9600波特率
5.因为我们需要同时实现输入输出功能,因此我们需要对代码进行一些修改,修改如下:
//在stdin中
#include "retarget_stdin.h"
#include "Driver_USART.h"
//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
// <h>STDIN USART Interface
// <o>Connect to hardware via Driver_USART# <0-255>
// <i>Select driver control block for USART interface
#define USART_DRV_NUM 1
// <o>Baudrate
#define USART_BAUDRATE 9600
// </h>
#define _USART_Driver_(n) Driver_USART##n
#define USART_Driver_(n) _USART_Driver_(n)
extern ARM_DRIVER_USART USART_Driver_(USART_DRV_NUM);
#define ptrUSART (&USART_Driver_(USART_DRV_NUM))
/**
Initialize stdin
\return 0 on success, or -1 on error.
*/
int stdin_init (void) {
int32_t status;
status = ptrUSART->Initialize(NULL);
if (status != ARM_DRIVER_OK) return (-1);
status = ptrUSART->PowerControl(ARM_POWER_FULL);
if (status != ARM_DRIVER_OK) return (-1);
status = ptrUSART->Control(ARM_USART_MODE_ASYNCHRONOUS |
ARM_USART_DATA_BITS_8 |
ARM_USART_PARITY_NONE |
ARM_USART_STOP_BITS_1 |
ARM_USART_FLOW_CONTROL_NONE,
USART_BAUDRATE);
if (status != ARM_DRIVER_OK) return (-1);
status = ptrUSART->Control(ARM_USART_CONTROL_RX, 1);
if (status != ARM_DRIVER_OK) return (-1);
status = ptrUSART->Control(ARM_USART_CONTROL_TX, 1);
if (status != ARM_DRIVER_OK) return (-1);
return (0);
}
/**
Get a character from stdin
\return The next character from the input, or -1 on read error.
*/
int stdin_getchar (void) {
uint8_t buf[1];
if (ptrUSART->Receive(buf, 1) != ARM_DRIVER_OK) {
return (-1);
}
while (ptrUSART->GetRxCount() != 1);
return (buf[0]);
}
//在stdout中
#include "retarget_stdout.h"
#include "Driver_USART.h"
//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
// <h>STDOUT USART Interface
// <o>Connect to hardware via Driver_USART# <0-255>
// <i>Select driver control block for USART interface
#define USART_DRV_NUM 1
// <o>Baudrate
#define USART_BAUDRATE 9600
// </h>
#define _USART_Driver_(n) Driver_USART##n
#define USART_Driver_(n) _USART_Driver_(n)
extern ARM_DRIVER_USART USART_Driver_(USART_DRV_NUM);
#define ptrUSART (&USART_Driver_(USART_DRV_NUM))
/**
Initialize stdout
\return 0 on success, or -1 on error.
*/
//int stdout_init (void) {
// int32_t status;
// status = ptrUSART->Initialize(NULL);
// if (status != ARM_DRIVER_OK) return (-1);
// status = ptrUSART->PowerControl(ARM_POWER_FULL);
// if (status != ARM_DRIVER_OK) return (-1);
// status = ptrUSART->Control(ARM_USART_MODE_ASYNCHRONOUS |
// ARM_USART_DATA_BITS_8 |
// ARM_USART_PARITY_NONE |
// ARM_USART_STOP_BITS_1 |
// ARM_USART_FLOW_CONTROL_NONE,
// USART_BAUDRATE);
// if (status != ARM_DRIVER_OK) return (-1);
// status = ptrUSART->Control(ARM_USART_CONTROL_TX, 1);
// if (status != ARM_DRIVER_OK) return (-1);
// return (0);
//}
/**
Put a character to the stdout
\param[in] ch Character to output
\return The character written, or -1 on write error.
*/
int stdout_putchar (int ch) {
uint8_t buf[1];
buf[0] = ch;
if (ptrUSART->Send(buf, 1) != ARM_DRIVER_OK) {
return (-1);
}
while (ptrUSART->GetTxCount() != 1);
return (ch);
}
6.添加main.c,进行io的输入输出测试
#include "stm32f10x.h"
#include "retarget_stdin.h"
#include "retarget_stdout.h"
void print(char str[])
{
for (int o = 0; o <= sizeof(str); o++)
{
stdout_putchar(str[o]);
}
}
int main(void)
{
stdin_init();
while(1)
{
int i = stdin_getchar();
if(i == 1)
{
print("hello");
}
}
}
编译通过,烧录测试,结果如下,完毕