STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK)

http://home.eeworld.com.cn/my/space-uid-338727-blogid-47176.html

在STM32串口通信程序中使用printf发送数据,非常的方便。可在刚开始使用的时候总是遇到问题,常见的是硬件访真时无法进入main主函数,其实只要简单的配置一下就可以了。
下面就说一下使用printf需要做哪些配置。
有两种配置方法:
一、对工程属性进行配置,详细步骤如下
1、首先要在你的main 文件中 包含“stdio.h” (标准输入输出头文件)。
2、在main文件中重定义<fputc>函数    如下:
// 发送数据int fputc(int ch, FILE *f){USART_SendData(USART1, (unsigned char) ch);// USART1 可以换成 USART2 等while (!(USART1->SR & USART_FLAG_TXE));return (ch);}// 接收数据int GetKey (void)    {while (!(USART1->SR & USART_FLAG_RXNE));return ((int)(USART1->DR & 0x1FF));}

这样在使用printf时就会调用自定义的fputc函数,来发送字符。
3、在工程属性的 “Target" -> "Code Generation" 选项中勾选 "Use MicroLIB"
MicroLIB 是缺省C的备份库,关于它可以到网上查找详细资料。
二、第二种方法是在工程中添加“Regtarge.c”文件
1、在main文件中包含 “stdio.h” 文件
2、在工程中创建一个文件保存为 Regtarge.c , 然后将其添加工程中在文件中输入如下内容(直接复制即可)
#include <stdio.h>
#include <rt_misc.h>
#pragma import(__use_no_semihosting_swi)
extern int  SendChar(int ch); // 声明外部函数,在main文件中定义
extern int  GetKey(void);
struct __FILE {int handle;                 // Add whatever you need here
};
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) {return (SendChar(ch));
}
int fgetc(FILE *f) {return (SendChar(GetKey()));
}
void _ttywrch(int ch) {SendChar (ch);
}
int ferror(FILE *f) {                            // Your implementation of ferrorreturn EOF;
}
void _sys_exit(int return_code) {
label:  goto label;           // endless loop
}

3、在main文件中添加定义以下两个函数

int SendChar (int ch)  {while (!(USART1->SR & USART_FLAG_TXE)); // USART1 可换成你程序中通信的串口USART1->DR = (ch & 0x1FF);return (ch);
}
int GetKey (void)  {while (!(USART1->SR & USART_FLAG_RXNE));return ((int)(USART1->DR & 0x1FF));
}

至此完成配置,可以在main文件中随意使用 printf 。

STM32程序添加printf函数后无法运行的解决方法(串口实验)

http://wojiushiwolxw.spaces.eepw.com.cn/articles/article/item/92847

标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数.

例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下:

只要自己添加一个int fputc(int ch, FILE *f)函数,能够输出字符就可以了

#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */USART_SendData(USART1, (uint8_t) ch);
  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
  return ch;
}

因printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,以下是解决方法:

方法1.使用微库,因为使用微库的话,不会使用半主机模式.

方法2.仍然使用标准库,在主程序添加下面代码:
#pragma import(__use_no_semihosting) _sys_exit(int x)
{ x = x;
}struct __FILE
{ int handle;
}; FILE __stdout;

IAR EWARM

General Options -- Library Configuration -- Library : Full < file descriptor support >

#include <stdio.h>#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{/* Place your implementation of fputc here *//* e.g. write a character to the USART */USART_SendData(USART1, (uint8_t) ch);/* Loop until the end of transmission */while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);return ch;
}

General Options -- Library Configuration -- Library : Normal < NO file descriptor support >

#include <stdio.h>size_t __write(int handle, const unsigned char * buffer, size_t size)
{
  // byte by byte write
}size_t __dwrite(int handle, const unsigned char * buffer, size_t size)
{// buffer[ 0x50 ]
}

Buffered Terminal Output : Enabled

xxwritebuffered.c

#define STORE_SIZE 80static size_t storeLen = 0;
static unsigned char store[STORE_SIZE];

uint8_t store[ 0x50 ];

uint32_t storelen;

printf() --> __dwrite() : buffer[0x50]

Buffered Terminal Output : Disabled

printf() --> __write(), byte by byte

自定义输出缓冲区

#define LOG_MAX_STR_LEN  512
void log_printf( const char * fmt, ... )
{char log_buf[ LOG_MAX_STR_LEN ];va_list args;va_start( args, fmt );int count = vsnprintf( log_buf, LOG_MAX_STR_LEN, fmt, args );va_end( args );// If an output error is encountered, a negative value is returned.if ( count < 0 )return;// "123456"    [123456][0X] : count = 6, n = 8// "1234567"   [1234567][0] : count = 7, n = 8// "12345678"  [1234567][0] : count = 8, n = 8// "123456789" [1234567][0] : count = 9, n = 8if ( count >= LOG_MAX_STR_LEN )count = LOG_MAX_STR_LEN - 1;// now log_buf is C string with the terminating null character__write(0, log_buf, count );
}

log_printf --> __write(), bufferred

stm32系列单片机之printf重定向

http://leon0820.blog.51cto.com/5893766/1440146

在程序的调试过程中,除了那些高大上的调试手段外,printf无疑是我们最熟悉最顺手的调试方法。

通过使用printf,我们可以很方便很直观的获取当前程序的运行状态。

printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。

但是在单片机开发中,一般情况下并不存在标准输出设备,因此我们需要将printf的输出信息重定向,也就是输出到其他输出设备中去。

在stm32平台上实现重定向的方式有两种,重定向至UART,或者通过JTAG的SW模式将printf重定向至SWO引脚输出。

首先介绍第一种,重定向至UART,这种方式我们比较熟悉,ST官方提供的固件库中也是使用的这种方法。

代码如下:在对UART进行初始化后,通过如下代码对printf进行重定向

int fputc(int ch, FILE *f)
{USART_SendData(USART1, (uint8_t) ch);/* Loop until the end of transmission */while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET){}return ch;
}

通过JTAG的SW模式将printf重定向至SWO引脚输出

1.在源码中添加对ITM端口寄存器的定义

#define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))#define DEMCR           (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA          0x01000000

2.通过如下代码将printf的输出重定向至ITM的Port 0

int fputc(int ch, FILE *f)
{if (DEMCR & TRCENA) {while (ITM_Port32(0) == 0);ITM_Port8(0) = ch;}return(ch);
}

3.通过printf输出调试信息

printf("AD value = 0x%04X\r\n", AD_value);

4.将Jtag设置为SW模式,并设置ITM的Port 0 获取信息。

STM32中重定向printf到SWO口

http://www.dashashi.com/index.php/2014/03/1488

printf在命令行编程的时候是非常常用的,虽然是个老函数,但是功能强大,经久不衰

51等8位单片机由于RAM比较小,栈就比较小,跑printf比较吃力,

但是STM32这种32位单片机跑printf就很容易了,而作为一种调试手段,printf十分方便、直观。

比较常见的方法是把printf重定向到串口,不过这需要外接一个串口线,比较麻烦。

其实STM32自带的SWO口是能够异步输出数据的,而且不需要外接什么设备,

ST-LINK/J-Link等带SWO口的调试器都支持。

下面以STM32F4Discovery开发板+GCC为例说明。

根据这里的方法,也可以把printf定位到其他外设。

PS:IAR在编译选项里自带了printf via SWO的功能,就不需要外加设置了。

http://community.silabs.com/t5/Microcontroller-How-to-Guides/SWO-printf-in-IAR/td-p/98257

首先来说说怎么把信息输出到SWO口,一句话搞定。

ITM_SendChar(ch);

这是在core_cm4.h(如果是F1系列的那就是core_cm3.h)中定义的内联函数。

不过不需要特意去include这个头文件,通过#include "stm32f4xx.h"就间接地将core_cm4.h包含进来。

不过说起来,ITM这个东西其实严格来说是Cortex-M提供的一个特性,而不是STM32。

利用这个函数把信息输出到SWO口之后再打开St-Link Utility,

在菜单里找到ST-LINK→Printf via SWO Viewer就会弹出一个窗口,

设置System Clock为单片机内核频率,点Start就能看到输出的信息了。

接下来就是把printf函数输出的字符串重定向过去了。

由于单片机的外设功能是根据需求变化的,编译器不可能确定printf需要用到的外设资源,

于是乎它就干脆留了个接口,也就是_write函数,

当然除了_write函数之外还有_read等其他函数,不过这里我们用不到。

其声明为 int _write(int fd, char* ptr, int len);

关于_write函数,说简单点,就是所有涉及到输出字符串的函数,

比如printf和putchar(),最终都会跑到_write函数,这里fd是文件标识符,说开来就比较复杂了,

这里我们用得到的就只有STDOUT_FILENO跟STDERR_FILENO,

其中前一个是标准输出的文件标识符的预定义变量,后一个是错误输出的文件标识符预定义变量。

第二个变量ptr是需要输出的字符串首地址,len就是输出长度。

当我们调用printf函数后,C运行库会把输入变量转换为最终需要输出的字符串,

然后调用_write函数,将结果输出。我们的工作就是实现一个_write函数。

新建一个_write.c文件,内容如下:

#include <stdio.h>
#include <unistd.h>#include "stm32f10x.h"#ifdef _DEBUGint _write(int fd, char* ptr, int len)
{
if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
{
int i = 0;
while(i<len)
ITM_SendChar(ptr[i++]);
}
return len;
}#endif

加了个#ifdef _DEBUG 的效果是未加 _DEBUG 定义的时候就忽略下面的东西,

因为这东西主要是用在调试阶段,RELEASE版本里面都用不到了,而且多少还是会影响速度。

其他东西就很简单了- -不需要多说明了吧。

直接编译能通过,但是链接会报错,提示无法找到_read之类的一堆函数。

在链接脚本的下面libgcc.a ( * )后面加上libnosys.a ( * ),就不会报错了。

具体原因涉及到Cortex-M3使用的newlib库的实现,就不具体展开了。

好吧好吧,其实我也不知道。

如果想把信息定位到串口,可以直接把ITM_SendChar改成相应的串口函数,

也可以利用DMA,先把数据拷贝到DMA缓冲区,让DMA自动传数据,提高响应速度。

STM32片内外设--DBG之Keil SWO输出

http://blog.sina.com.cn/s/blog_79b01f6601018ymr.html

1) 加入stdio.h,这样你就可以调用printf函数了

2) 使能SWO输出

使能SWO输出。最简单的办法就是将如下的函数拷贝到你的工程里面,并且在mian函数初始化之后调用该函数。

void setupSWO(void)
{
uint32_t *dwt_ctrl = (uint32_t *) 0xE0001000;
uint32_t *tpiu_prescaler = (uint32_t *) 0xE0040010;
uint32_t *tpiu_protocol = (uint32_t *) 0xE00400F0;CMU->HFPERCLKEN0 |= CMU_HFPERCLKEN0_GPIO;GPIO->ROUTE |= GPIO_ROUTE_SWOPEN;
#if defined(_EFM32_GIANT_FAMILY)GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC0;GPIO->P[5].MODEL &= ~(_GPIO_P_MODEL_MODE2_MASK);
GPIO->P[5].MODEL |= GPIO_P_MODEL_MODE2_PUSHPULL;
#elseGPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC1;GPIO->P[2].MODEH &= ~(_GPIO_P_MODEH_MODE15_MASK);
GPIO->P[2].MODEH |= GPIO_P_MODEH_MODE15_PUSHPULL;
#endifCMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;while(!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY));CoreDebug->DHCSR |= 1;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;*dwt_ctrl = 0x400113FF;*tpiu_prescaler = 0xf;*tpiu_protocol = 2;ITM->LAR = 0xC5ACCE55;
ITM->TCR = 0x10009;
}

3) 配置Keil的工程选项

打开Keil的工程配置,选择Debug页面,选择仿真器为Cortex-M/R J-Link/J-Trace, 并点击仿真器选项边上的setting选项,打开具体的设置窗口。

在打开的窗口中,切换到Trace页面,选中Enable,并且设置Core Clock为14MHz,分频选项为Core Clock/16。详情如下:

4) 在初始化SWO函数之后的地方,使用printf函数进行输出。例如printf("Hello world")。

5) 在你的工程里面,需要添加如下的函数:

struct __FILE {   int handle; };
FILE __stdout;
FILE __stdin;int fputc(int ch, FILE *f) {ITM_SendChar(ch);
  return(ch);
}

6) 编译你的代码,并且进入Debug状态

7) 打开Keil的printf-view窗口, 通过 View -> Serial Windows -> Debug(printf) View

8) 点击运行之后,在Debug (printf) View里即可查看

Debug (printf) Viewer

http://www.keil.com/support/man/docs/jlink/jlink_trace_itm_viewer.htm

Segger RTT : Real Time Terminal

http://segger.com/jlink-real-time-terminal.html

转载于:https://www.cnblogs.com/shangdawei/p/3970489.html

STM32 使用 printf 发送数据配置方法 -- 串口 UART, JTAG SWO, JLINK RTT相关推荐

  1. STM32串口通信中使用printf发送数据配置方法 开发环境 Keil

    STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) 已有 12456 次阅读2011-6-29 23:29 | 在STM32串口通信程序中使用printf发送数据, ...

  2. STM32单片机ESP8266发送数据到WiFi接收端代码实现

    ESP8266支持的一些指令看我另一篇博文:http://blog.csdn.net/qq_17242837/article/details/53931712 首先需要配置STM32的串口发送和接收, ...

  3. STM32f407与STM32F103 串口采用DMA收发数据配置方法的异同

    最近有个项目需要用到STM32F407ZET6这款芯片,其中有一个串口收发数据的应用.因为之前有用过STMF32F103ZET6通过DMA收发数据的方案,所以我打算移植之前的代码实现这个功能,STM3 ...

  4. 【STM32学习5】STM32使用printf函数 打印到电脑串口助手

    本文所使用的方法与代码参考自正点原子,如果想要详细了解这方面的知识,请阅读正点原子官方提供的文档. 一.背景 在开发STM32应用时,将一些信息通过串口打印到电脑上是常用的调试手段.C语言标准库中的p ...

  5. linux串口发送数据程序,linux串口驱动分析——发送数据

    一.应用程序中write函数到底层驱动历程 和前文提到的一样,首先先注册串口,使用uart_register_driver函数,依次分别为tty_register_driver,cdev_init函数 ...

  6. 【无标题】Android在activity之间发送数据(putExtra方法)

    Activity 之间发送数据(putExtra方法详解) 当应用创建 Intent 对象以在 startActivity(android.content.Intent) 中用于启动新的 Activi ...

  7. STM32工作笔记0053---STM32串口寄存器库函数配置方法+串口通信实例

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152

  8. STM32的USART发送数据时如何使用TXE和TC标志

    在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register). ...

  9. python 服务端主动发数据_python使用socket向客户端发送数据的方法

    Python Socket通讯例子详解 创新从模仿开始! python中内置的socket模块使得网络编程更加简单化,下面就通过两个小小脚本来了解客户端如何与服务器端建立socket. 客户端代码: ...

  10. STM32串口发送数据和接收数据方式总结

    文章目录 串口发送数据 串口接受数据 串口发送数据 1.串口发送数据最直接的方式就是标准调用库函数 . void USART_SendData(USART_TypeDef* USARTx, uint1 ...

最新文章

  1. 多选框实现单选效果,并且把中文值赋值到特定输入框
  2. 20180530更新
  3. 制作一个功能丰富的Android天气App
  4. xp故障恢复控制台和它的命令
  5. TCP/IP 协议簇的逐层封装
  6. win10下如何安装vb6.0sp6_Mac如何安装win10系统?Parallels Desktop 15 Mac安装win10系统教程...
  7. 3项目里面全局用less变量 cli vue_vue-cli3配置使用vw实现移动端适配案例
  8. 记一个 DataBindings遇到的坑,当ComboBox同时绑定DataSource与DataBindings的时候,绑定的元素一定要同名...
  9. Struts如何获取客户端ip地址
  10. 从csrss弹出的ASSERT对话框谈起
  11. 【每天学一点新知识】getshell???webshell???
  12. PS3模拟器RPCS3无法识别PS3手柄 且无振动的解决办法
  13. solidity 中的时间_Solidity官方文档中文版.pdf
  14. Bert 得到中文词向量
  15. windows 查找目录下文件中包含某个字符的文件
  16. (python)BMI计算
  17. 802.11与802.3数据帧转换(即有线和无线数据帧转换)
  18. 本人亲测,可以使用,万网虚拟主机绑定多个子域名方法(转载)
  19. 大数据的架构设计与未来
  20. 二手车 电商+互联网金融的三种新玩法

热门文章

  1. 一般性网络错误 请检查网络文档_“网络工程团队”公众号投稿须知!
  2. eyoucms 网页制作软件有哪些 这些你都知道吗
  3. 故障处理,no space left on device!几种可能性?
  4. 关于用data开头属性的取值
  5. 安全分析:叫好不叫座
  6. centos6.9下设置nginx服务开机自动启动
  7. lua与c若干问题 - 专职C++ - C++博客
  8. Intel CPU命名规则
  9. biztalk中常用调试方法
  10. 【Webcam设计】视频的采集和动态显示