历史上的今天

今天是:2024年10月13日(星期日)

正在发生

2018年10月13日 | STM32中printf与scanf的实现问题

发布者:红尘清梦 来源: eefocus关键字:STM32  printf  scanf 手机看文章 扫描二维码
随时随地手机看文章

#include "sys.h"

#include "usart3.h"      

#include "stdarg.h"          

#include "stdio.h"          

#include "string.h"

#include "timer.h" 

//串口发送缓存区     

__align(8) u8 USART3_TX_BUF[USART3_MAX_SEND_LEN];     //发送缓冲,最大USART3_MAX_SEND_LEN字节

//串口接收缓存区     

u8 USART3_RX_BUF[USART3_MAX_RECV_LEN];                       //接收缓冲,最大USART3_MAX_RECV_LEN个字节.

//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.

//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到

//任何数据,则表示此次接收完毕.

//接收到的数据状态

//[15]:0,没有接收到数据;1,接收到了一批数据.

//[14:0]:接收到的数据长度

vu16 USART3_RX_STA=0;

void USART3_IRQHandler(void)

{

    u8 res;

    if(USART3->SR&(1<<5))//接收到数据

    {

        res=USART3->DR;

        if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据

        {

            if(USART3_RX_STA

            {

                TIM7->CNT=0;                         //计数器清空

                if(USART3_RX_STA==0)                 //使能定时器7的中断

                {

                    TIM7->CR1|=1<<0;                 //使能定时器7

                }

                USART3_RX_BUF[USART3_RX_STA++]=res;  //记录接收到的值

            }

            else 

            {

                USART3_RX_STA|=1<<15;                //强制标记接收完成

            } 

        }

    }                                                       

}   

//初始化IO 串口3

//pclk1:PCLK1时钟频率(Mhz)

//bound:波特率 

void usart3_init(u32 pclk1,u32 bound)

{       

    float temp;

    u16 mantissa;

    u16 fraction;       

    temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV,OVER8设置为0

    mantissa=temp;                         //得到整数部分

    fraction=(temp-mantissa)*16;           //得到小数部分,OVER8设置为0     

    mantissa<<=4;

    mantissa+=fraction; 

    RCC->AHB1ENR|=1<<1;               //使能PORTB口时钟  

    RCC->APB1ENR|=1<<18;              //使能串口3时钟 

   GPIO_Set(GPIOB,PIN10|PIN11,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PB10,PB11,复用功能,上拉输出

     GPIO_AF_Set(GPIOB,10,7);         //PB10,AF7

    GPIO_AF_Set(GPIOB,11,7);          //PB11,AF7         

    //波特率设置

     USART3->BRR=mantissa;            // 波特率设置     

    USART3->CR1|=1<<3;                //串口发送使能  

    USART3->CR1|=1<<2;                //串口接收使能

    USART3->CR1|=1<<5;                //接收缓冲区非空中断使能    

    USART3->CR1|=1<<13;               //串口使能  

    MY_NVIC_Init(0,2,USART3_IRQn,2);  //组2,优先级0,2,最高优先级 

    TIM7_Int_Init(100-1,9000-1);      //10ms中断一次

    TIM7->CR1&=~(1<<0);               //关闭定时器7

    USART3_RX_STA=0;                  //清零 

}

//串口3,printf 函数

//确保一次发送数据不超过USART3_MAX_SEND_LEN字节

void u3_printf(char* fmt,...)  

{  

    u16 i,j;

    va_list ap;

    va_start(ap,fmt);

    vsprintf((char*)USART3_TX_BUF,fmt,ap);

    va_end(ap);

    i=strlen((const char*)USART3_TX_BUF);//此次发送数据的长度

    for(j=0;j

    {

        while((USART3->SR&0X40)==0);     //循环发送,直到发送完毕   

        USART3->DR=USART3_TX_BUF[j];  

    }

}

=================================================================

#include "sys.h"

#include "usart.h"      

//加入以下代码,支持printf函数,而不需要选择use MicroLIB      

#if 1

#pragma import(__use_no_semihosting)  

//解决HAL库使用时,某些情况可能报错的bug

int _ttywrch(int ch)    

{

    ch=ch;

    return ch;

}

//标准库需要的支持函数                 

struct __FILE 

    int handle; 

    // Whatever you require here. If the only file you are using is  

    // standard output using printf() for debugging, no file handling  

    // is required.  

}; 

// FILE is typedef’ d in stdio.h.  

FILE __stdout;       

//定义_sys_exit()以避免使用半主机模式    

void _sys_exit(int x) 

    x = x; 

//重定义fputc函数 

int fputc(int ch, FILE *f)

{      

    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   

    USART1->DR = (u8) ch;      

    return ch;

}

#endif 

//////////////////////////////////////////////////////////////////

#if EN_USART1_RX      //如果使能了接收

//串口1中断服务程序

//注意,读取USARTx->SR能避免莫名其妙的错误       

u8 USART_RX_BUF[USART_REC_LEN];   //接收缓冲,最大USART_REC_LEN个字节.

//接收状态

//bit15,    接收完成标志

//bit14,    接收到0x0d

//bit13~0,    接收到的有效字节数目

u16 USART_RX_STA=0;   //接收状态标记      

  

void USART1_IRQHandler(void)

{

    u8 res;    

#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.

    OSIntEnter();    

#endif

    if(USART1->SR&(1<<5))//接收到数据

    {     

        res=USART1->DR; 

        if((USART_RX_STA&0x8000)==0)//接收未完成

        {

            if(USART_RX_STA&0x4000) //接收到了0x0d

            {

                if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始

                else USART_RX_STA|=0x8000;  //接收完成了 

            }

            else //还没收到0X0D

            {    

                if(res==0x0d)USART_RX_STA|=0x4000;

                else

                {

                    USART_RX_BUF[USART_RX_STA&0X3FFF]=res;

                    USART_RX_STA++;

                    if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收      

                }         

            }

        }                                                    

    } 

#if SYSTEM_SUPPORT_OS     //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.

    OSIntExit();                                               

#endif

}

#endif                                         

//初始化IO 串口1

//pclk2:PCLK2时钟频率(Mhz)

//bound:波特率 

void uart_init(u32 pclk2,u32 bound)

{       

    float temp;

    u16 mantissa;

    u16 fraction;       

    temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV@OVER8=0

    mantissa=temp;               //得到整数部分

    fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0 

    mantissa<<=4;

    mantissa+=fraction; 

    RCC->AHB1ENR|=1<<0;          //使能PORTA口时钟  

    RCC->APB2ENR|=1<<4;          //使能串口1时钟 

   GPIO_Set(GPIOA,PIN9|PIN10,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PA9,PA10,复用功能,上拉输出

     GPIO_AF_Set(GPIOA,9,7);     //PA9,AF7

    GPIO_AF_Set(GPIOA,10,7);//PA10,AF7         

    //波特率设置

     USART1->BRR=mantissa;       //波特率设置     

    USART1->CR1&=~(1<<15);       //设置OVER8=0 

    USART1->CR1|=1<<3;           //串口发送使能 

#if EN_USART1_RX                 //如果使能了接收

    //使能接收中断 

    USART1->CR1|=1<<2;           //串口接收使能

    USART1->CR1|=1<<5;           //接收缓冲区非空中断使能            

    MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级 

#endif

    USART1->CR1|=1<<13;          //串口使能

}

=================================================================

STM32中printf与scanf的重定向问题:http://blog.csdn.net/l_yankui/article/details/53452738

关于STM32中 printf 与 scanf 的重定向问题在此我仅对不使用 "USE MircoLIB" 的情况做整理(针对Keil RVMDK开发环境)。

① :首先需要在 usart.h 中包含 “stdio.h” 头文件

② :在 usart.c 中,加入如下代码块,以此避免使用半主机模式,并重定向 printf 和scanf 函数;

#if 1  

#pragma import (__use_no_semihosting_swi)  

//标准库需要的支持函数,use_no_semihosting_swi以避免使用半主机模式  

struct __FILE  

{  

    int handle;  

};  

  

FILE __stdout;  

FILE __stdin;  

//重定向Printf函数  

int fputc(int ch,FILE *f)  

{  

    return (SendChar(ch));  

}  

//重定向Scanf函数  

int fgetc(FILE *f)  

{  

    return (SendChar(GetKey()));  

    //调用scanf()在串口中输入数据时,必须以空格结束,否则无法完成发送  

}  

void _ttywrch(int ch)  

{  

    SendChar(ch);  

}  

int _ferror(FILE *f) {  

  // Your implementation of ferror   

  return EOF;  

}  

//定义_sys_exit()以避免使用半主机模式  

void _sys_exit(int return_code){  

    //x = x;  

label:goto label;  

}  

#endif  

③ :在 usart.c 中添加SendChar()与GetKey()函数

[plain] view plain copy

int SendChar(int ch)  

{  

    while(!(USART1->SR & USART_FLAG_TXE));  

    USART1->DR = (ch & 0x1FF);  

  

    return ch;  

  

int GetKey(void)  

{  

    while(!(USART1->SR & USART_FLAG_RXNE));  

    return ((int)(USART1->DR & 0X1FF));  

}  

完成以上三步,即可实现printf()函数与scanf()的串口重定向,将标准输入输出流的来源或去向改为串口。

关于第二步所使用的避免使用半主机模式的代码,其实Kei已经为我们写好了一个Retarget.c文件,在Keil/ARM/Startup目录下.

另外本文针对的开发环境为Keil RVMDK,本人在Emblocks开源开发工具中实验时,本方法是无法实现printf和Scanf的重定向的,以及在开源工具下如何"Use microLIB"的问题都有待进一步探讨。


关键字:STM32  printf  scanf 引用地址:STM32中printf与scanf的实现问题

上一篇:stm32如何改变PC(R15)的值?
下一篇:进入存量市场,硬件巨头要开辟哪些新市场?

推荐阅读

   “智能时代将诞生硬件新巨头,我不讳言寒武纪想当这个将军。”  AI芯片是科技行业最惹人注目的赛道。寒武纪是这个赛道上最惹人注目的成长期公司。贸易战关口,这里的一草一木更是彻底暴露于聚光灯下。  在今年初完成数亿美元B轮融资后,寒武纪投后估值已达25亿美元,成为中国人工智能芯片领域的头部独角兽。作为“中国第一家作出最原始创新(从学...
消防产业属于保障性安全产业,其发展对于国家的长治久安和促进社会进步具有重要意义。据Grand View Research发布的报告显示,全球消防安全设备市场规模预计到2025年将成长至1059.2亿美元,年复合增长率约为8.8%。 消防机器人作为一种特殊的装备,能够代替消防员进入有毒、浓烟、高温、缺氧等高危险性现场完成侦查、排烟降温、搜索救人、灭火控制等...
白蚁被国际昆虫生态研究中心列为世界五大害虫之一,全球每年因白蚁对房屋建筑、水利电力、文物古建、风景园林、农林果木造成的直接经济损失多达数百亿美元。如何科学有效地防治白蚁,有赖于更为专业的检测工具和整治方法。 区别于传统依赖人工的“看、听、探、撬”的白蚁防治手段,其成本高、破坏大、治标不治本,而利用更为专业的红外热像仪对建筑的安全...
据外媒报道,当地时间10月11日,帮助企业和组织激活大数据的技术开发商Tsecond推出了一个强大且独一无二的解决方案BRYCK,其可以轻松地从任何地方捕获、处理和存储数据。用户可以在该便携式媒体设备BRYCK中收集多达1PB的数据,并且以极快的速度进行存储和恢复,而且该设备非常小,可以单手携带,也非常坚固,可应对最恶劣的环境。BRYCK可应用于数据密集型...

史海拾趣

问答坊 | AI 解惑

罗克韦尔自动化控制系统在汽车生产线中的应用

罗克韦尔自动化控制系统提高了汽车生产线的效率,而同时又将停工时间减少了10%——并且将整体生产成本降低2%。 背景:   某汽车有限公司是国内知名的合资企业。2001年5月开始,生产在中国最受欢迎的两种卡车。该公司拥有中国 ...…

查看全部问答∨

基于边界扫描技术的电路板可测性设计分析

现代电子技术的高速发展对传统的电路测试技术提出了新的挑战。器件封装的小型化、表面贴装(SMT)技术的应用,以及由于板器件密度的加大而出现的多层印制板技术使得电路节点的物理可访问性逐步减低,原来借助于针床的在线测试(ICT)的局限性日益增大。 ...…

查看全部问答∨

请教我设计的按键控制为什么按住jia或jian键后程序会停止?

#include <reg52.h> #define uchar unsigned char #define uint unsigned int uchar bb;  //定时器中断次数 。 uchar m;  //个位秒。 uchar tt;  //十位秒。 uchar tt1;  // 个位分。 uchar tt ...…

查看全部问答∨

触摸屏,大家开始用了么?

小弟最近关注触摸屏相关的技术,但是具备的相关经验甚少。只是记得Cypress之前一直在推电容感应触摸屏。 大家在实际中,用过触摸屏么?用的什么屏?觉得如何?…

查看全部问答∨

除了身高其他都很保守的简历。

**,您好:   小明。男。1986年17月40日出生。身高190,体重80KG。籍贯山东省济南市。信仰无神论力量崇拜。身体优良。未婚。爱好计算机,吉他,铅笔画,篮球,游泳,做饭。性格柔中带钢,讲原则,重诚信。   2005年9月入读乌 ...…

查看全部问答∨

(高分请教)有了解“广东亿迅,普信科技有限公司”的朋友请进

想了解一下“广东亿迅,普信科技有限公司”      1、该公司的总体情况如何;      2、与“广东电信研究院”的关系      谢谢    …

查看全部问答∨

关于STM8S207的内存变量

大家好,求助STM3S207的变量定义。 使用的是STVD开发环境,C语言编程,很不好用,呵呵! 定义了超过256个字节的变量,链接的时候报错,说是page0没有空间了。 我也检查了map文件,果然所有的变量都定义在了0~0xFF。但让我奇怪的是207号称有 ...…

查看全部问答∨

如何计算有效值和谐波含量?

采样数据如下:lBFUIN[256] ={1026,1032,1039,1045,1052,1058,1066,1073,1081,1087,1095,1104,1113,1121,1129,1138,1146,1155,1165,1172,1183,1192,1201,1212,1222,1231,1242,1251,1262,1272,1284,1294,1303,1313,1324,1335,1346,1356,13 ...…

查看全部问答∨

关于Keil uVision3软件的应用

我用的这个Keil uVision3软件,发现光标对应的字会有偏移,不知道大家有没有这情况,怎么解决…

查看全部问答∨

招聘高级硬件工程师(地点:成都)

职位要求:   1、本科以上学历,通信、电子、自动化、计算机或相关专业,五年以上工作经验;   2、从事多年硬件开发工作,熟练掌握相关硬件开发工具,熟悉硬件开发流程;   3、精通嵌入式处理器原理,熟悉X86/Pow ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved