STM32
登录
直播中
王锦霞
8年用户
1020经验值
私信
关注
[问答]
为什么使用MDK进行嵌入式开发其程序却无法正常运行呢
开启该帖子的消息推送
MDK
嵌入式开发
串口
为什么使用MDK进行嵌入式开发其程序却无法正常运行呢?
51
单片机
通过printf()与串口结合发送数据到串口调试工具的代码该如何去编写?
回帖
(1)
周娟
2021-11-30 15:41:44
在使用MDK进行嵌入式开发,特别是调试串口的时候经常要用到C语言的标准输入输出库函数,如printf();。这样写出来的程序,通常编译和链接过程都不会报错,但是程序却无法正常运行.
原因分析如下:
标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数.
例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下: 只要自己添加一个int fputc(int ch, FILE *f)函数,能够输出字符就可以了
int fputc(int ch, FILE *f)
{
UART0_D = ch;
while(!((UART0_S1)& 0x40));
return ch;
}
因为printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,以下是解决方法:
方法1.使用微库,因为使用微库的话,不会使用半主机模式。
如果使用的是MDK,请在工程属性的“Target“-》”Code Generation“中勾选”Use MicroLIB“这样以后就可以使用printf,sprintf函数了
方法2.仍然使用标准库,但在主程序中需要添加以下代码:
/*因为不使用半主机模式,所以标准C库stdio.h中有些使用半主机的函数需要重新写*/
#pragma import(__use_no_semihosting) //确保没有从 C 库链接使用半主机的函数
_sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{ x = x; }
struct __FILE //标准库需要的支持函数
{
int handle;
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
int fputc(int ch, FILE *f)
{
UART0_D = ch; //发送数据缓存区
while(!((UART0_S1)& 0x40)); //串口发送中断标志位,等待发送完成
//如果中断标志位 = 0,则等待;while(!中断标志位)
return ch;
}
在独立应用程序中,不太可能支持半主机操作。 因此,必须确保您的应用程序中没有链接 C 库半主机函数。
为确保没有从 C 库链接使用半主机的函数,必须导入符号 __use_no_semihosting。可在工程的任何 C 或汇编语言源文件中执行此操作,如下所示:
在 C 模块中,使用 #pragma 指令:
#pragma import(__use_no_semihosting)
在汇编语言模块中,使用 IMPORT 指令:
IMPORT __use_no_semihosting
如果仍然链接了使用半主机的函数,则链接器就会报告错误
下面是网上关于半主机模式的解释:
【半主机是用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。 例如,使用此机制可以启用 C 库中的函数,如 printf() 和 scanf(),来使用主机的屏幕和键盘,而不是在目标系统上配备屏幕和键盘。
这种机制很有用,因为开发时使用的硬件通常没有最终系统的所有输入和输出设备。 半主机可让主机来提供这些设备。
半主机是通过一组定义好的软件指令(如 SVC)来实现的,这些指令通过程序控制生成异常。 应用程序调用相应的半主机调用,然后调试代理处理该异常。 调试代理提供与主机之间的必需通信。
半主机接口对 ARM 公司提供的所有调试代理都是通用的。 在无需移植的情况下使用 RealView ARMulator ISS、指令集系统模型 (ISSM)、实时系统模型 (RTSM)、RealView ICE 或 RealMonitor 时,会执行半主机操作,请参阅Figure 8.1。
在很多情况下,半主机由库函数内的代码调用。 应用程序还可以直接调用半主机操作。 有关 ARM C 库中的半主机支持的详细信息,请参阅《库和浮点支持指南》中的第 2 章 C 和 C++ 库。】
下面是51单片机通过printf()与串口结合发送数据到串口调试工具的代码如下:
#include
#include
#define uchar unsigned char
#define uint unsigned int
void uart_init();
uint i = 0;
//UART发送串口数据
void UART_SendData(char dat)
{
ES=0; //关串口中断
SBUF=dat;
while(TI!=1); //等待发送成功
TI=0; //清除发送中断标志
ES=1; //开串口中断
}
//UART 发送字符串
void UART_SendString(char *s)
{
while(*s)//检测字符串结束符
{
UART_SendData(*s++);//发送当前字符
}
}
//重写putchar函数
char putchar(char c)
{
UART_SendData(c);
return c;
}
void main()
{
uart_init();
while(1)
{
UART_SendString("qqqqqqqqqqqqqqqqqqqqqqrn");
printf("i = %drn",i++);
}
}
void uart_init()
{
TMOD=0x20; //定时器的工作方式2;
TH1=0xfd; //波特率9600
TL1=0xfd;
TR1=1; //启动定时器1;
SM0=0; // 方式一:10位(8位数据位,1,一个起始位,1个停止位)
SM1=1;
REN=1; //先允许串口接收
EA=1; //全中断(总中断)
ES=1; // 串口中断
}
在使用MDK进行嵌入式开发,特别是调试串口的时候经常要用到C语言的标准输入输出库函数,如printf();。这样写出来的程序,通常编译和链接过程都不会报错,但是程序却无法正常运行.
原因分析如下:
标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数.
例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下: 只要自己添加一个int fputc(int ch, FILE *f)函数,能够输出字符就可以了
int fputc(int ch, FILE *f)
{
UART0_D = ch;
while(!((UART0_S1)& 0x40));
return ch;
}
因为printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,以下是解决方法:
方法1.使用微库,因为使用微库的话,不会使用半主机模式。
如果使用的是MDK,请在工程属性的“Target“-》”Code Generation“中勾选”Use MicroLIB“这样以后就可以使用printf,sprintf函数了
方法2.仍然使用标准库,但在主程序中需要添加以下代码:
/*因为不使用半主机模式,所以标准C库stdio.h中有些使用半主机的函数需要重新写*/
#pragma import(__use_no_semihosting) //确保没有从 C 库链接使用半主机的函数
_sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{ x = x; }
struct __FILE //标准库需要的支持函数
{
int handle;
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
int fputc(int ch, FILE *f)
{
UART0_D = ch; //发送数据缓存区
while(!((UART0_S1)& 0x40)); //串口发送中断标志位,等待发送完成
//如果中断标志位 = 0,则等待;while(!中断标志位)
return ch;
}
在独立应用程序中,不太可能支持半主机操作。 因此,必须确保您的应用程序中没有链接 C 库半主机函数。
为确保没有从 C 库链接使用半主机的函数,必须导入符号 __use_no_semihosting。可在工程的任何 C 或汇编语言源文件中执行此操作,如下所示:
在 C 模块中,使用 #pragma 指令:
#pragma import(__use_no_semihosting)
在汇编语言模块中,使用 IMPORT 指令:
IMPORT __use_no_semihosting
如果仍然链接了使用半主机的函数,则链接器就会报告错误
下面是网上关于半主机模式的解释:
【半主机是用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。 例如,使用此机制可以启用 C 库中的函数,如 printf() 和 scanf(),来使用主机的屏幕和键盘,而不是在目标系统上配备屏幕和键盘。
这种机制很有用,因为开发时使用的硬件通常没有最终系统的所有输入和输出设备。 半主机可让主机来提供这些设备。
半主机是通过一组定义好的软件指令(如 SVC)来实现的,这些指令通过程序控制生成异常。 应用程序调用相应的半主机调用,然后调试代理处理该异常。 调试代理提供与主机之间的必需通信。
半主机接口对 ARM 公司提供的所有调试代理都是通用的。 在无需移植的情况下使用 RealView ARMulator ISS、指令集系统模型 (ISSM)、实时系统模型 (RTSM)、RealView ICE 或 RealMonitor 时,会执行半主机操作,请参阅Figure 8.1。
在很多情况下,半主机由库函数内的代码调用。 应用程序还可以直接调用半主机操作。 有关 ARM C 库中的半主机支持的详细信息,请参阅《库和浮点支持指南》中的第 2 章 C 和 C++ 库。】
下面是51单片机通过printf()与串口结合发送数据到串口调试工具的代码如下:
#include
#include
#define uchar unsigned char
#define uint unsigned int
void uart_init();
uint i = 0;
//UART发送串口数据
void UART_SendData(char dat)
{
ES=0; //关串口中断
SBUF=dat;
while(TI!=1); //等待发送成功
TI=0; //清除发送中断标志
ES=1; //开串口中断
}
//UART 发送字符串
void UART_SendString(char *s)
{
while(*s)//检测字符串结束符
{
UART_SendData(*s++);//发送当前字符
}
}
//重写putchar函数
char putchar(char c)
{
UART_SendData(c);
return c;
}
void main()
{
uart_init();
while(1)
{
UART_SendString("qqqqqqqqqqqqqqqqqqqqqqrn");
printf("i = %drn",i++);
}
}
void uart_init()
{
TMOD=0x20; //定时器的工作方式2;
TH1=0xfd; //波特率9600
TL1=0xfd;
TR1=1; //启动定时器1;
SM0=0; // 方式一:10位(8位数据位,1,一个起始位,1个停止位)
SM1=1;
REN=1; //先允许串口接收
EA=1; //全中断(总中断)
ES=1; // 串口中断
}
举报
更多回帖
rotate(-90deg);
回复
相关问答
MDK
嵌入式开发
串口
嵌入式开发
是指什么?
嵌入式
有何应用
呢
2022-01-24
2079
如何从零开始学习
嵌入式开发
技术?
2021-04-02
1638
如何使用eop烧写
嵌入式开发
板的裸板
程序
呢
2021-12-27
1165
嵌入式开发
要学什么
2021-01-18
2743
嵌入式开发
板
开发
与SOC系统
开发
有哪些不同之处
呢
2021-12-27
2081
嵌入式开发
工具面临的挑战是什么?未来的发展趋势
呢
?
2021-04-27
1974
嵌入式开发
与Python编程有哪些区别及其联系
呢
2021-12-24
2711
怎样去修改iMX6UL
嵌入式开发
板的主频
呢
2021-12-27
1456
什么样的人适合转行
嵌入式开发
?
2018-09-20
3524
在
嵌入式开发
板上如何用opencv调用caffe模型
进行
人脸识别并截图
呢
2021-12-27
1175
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分