36. printf

1. printf

格式化函数说的是 printf、 sprintf 和 scanf 这样的函数,分为格式化输入和格式化输出两类函数。学习 C 语言的时候常常通过 printf 函数在屏幕上显示字符串,通过 scanf 函数从键盘获取输入。这样就有了输入和输出了,实现了最基本的人机交互。学习 STM32 的时候会将 printf 映射到串口上,这样即使没有屏幕,也可以通过串口来和开发板进行交互。在 I.MX6U-ALPHA 开发板上也可以使用此方法,将 printf 和 scanf 映射到串口上,这样就可以使用 SecureCRT 作为开发板的终端,完成与开发板的交互。也可以使用 printf 和 sprintf 来实现各种各样的格式化字符串,方便我们后续的开发。 文件夹 stdio 里面的文件就是我们要移植的源码文件。
在这里插入图片描述

图 22.3.2 就是 stdio 里面的所有文件, stdio 里面的文件其实是从 uboot 里面移植过来的。后面学习 uboot 以后大家有兴趣的话可以自行从 uboot 源码里面“扣”出相应的文件,完成格式化函数的移植。这里要注意一点, stdio 中并没有实现完全版的格式化函数,比如 printf 函数并不支持浮点数,但是基本够我们使用了。

2.代码

//bsp_uart.c

#include "bsp_uart.h"/** @description : 初始化串口1,波特率为115200* @param       : 无* @return      : 无*/
void uart_init(void)
{/* 1、初始化串口IO            */uart_io_init();/* 2、初始化UART1           */uart_disable(UART1);    /* 先关闭UART1         */uart_softreset(UART1);  /* 软件复位UART1        */UART1->
UCR1 = 0;       /* 先清除UCR1寄存器 *//** 设置UART的UCR2寄存器,设置内容包括字长,停止位,校验模式,关闭RTS硬件流控* bit14: 1 忽略RTS引脚* bit8: 0 关闭奇偶校验* bit6: 0 1位停止位* bit5: 1 8位数据位* bit2: 1 打开发送* bit1: 1 打开接收*/UART1->UCR2 |= (1<<14) | (1<<5) | (1<<2) | (1<<1);/** UART1的UCR3寄存器* bit2: 1 必须设置为1!参考IMX6ULL参考手册3642页*/UART1->UCR3 |= 1<<2; /** 设置UART的UCR1寄存器,关闭自动波特率* bit14: 0 关闭自动波特率检测,我们自己设置波特率*/UART1->UCR1 &= ~(1<<14);#if 0  //也可用/** 设置波特率* 波特率计算公式:Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)) * 如果要设置波特率为115200,那么可以使用如下参数:* Ref Freq = 80M 也就是寄存器UFCR的bit9:7=101, 表示1分频* UBMR = 3124* UBIR =  71* 因此波特率= 80000000/(16 * (3124+1)/(71+1))=80000000/(16 * 3125/72) = (80000000*72) / (16*3125) = 115200*/UART1->UFCR = 5<<7; //ref freq等于ipg_clk/1=80MhzUART1->UBIR = 71;UART1->UBMR = 3124;#endifuart_setbaudrate(UART1,115200,80000000);/* 使能串口 */uart_enable(UART1);
}/** @description : 初始化串口1所使用的IO引脚* @param       : 无* @return      : 无*/
void uart_io_init(void)
{/* 1、初始化IO复用 * UART1_RXD -> UART1_TX_DATA* UART1_TXD -> UART1_RX_DATA*/IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0);  /* 复用为UART1_TX */IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0);  /* 复用为UART1_RX *//* 2、配置UART1_TX_DATA、UART1_RX_DATA的IO属性 *bit 16:0 HYS关闭*bit [15:14]: 00 默认100K下拉*bit [13]: 0 keeper功能*bit [12]: 1 pull/keeper使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 驱动能力R0/6*bit [0]: 0 低转换率*/IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0);
}/** @description         : 波特率计算公式,*                        可以用此函数计算出指定串口对应的UFCR,*                        UBIR和UBMR这三个寄存器的值* @param - base        : 要计算的串口。* @param - baudrate    : 要使用的波特率。* @param - srcclock_hz :串口时钟源频率,单位Hz* @return      : 无*/
void uart_setbaudrate(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz)
{uint32_t numerator = 0u;        //分子uint32_t denominator = 0U;      //分母uint32_t divisor = 0U;uint32_t refFreqDiv = 0U;uint32_t divider = 1U;uint64_t baudDiff = 0U;uint64_t tempNumerator = 0U;uint32_t tempDenominator = 0u;/* get the approximately maximum divisor */numerator = srcclock_hz;denominator = baudrate << 4;divisor = 1;while (denominator != 0){divisor = denominator;denominator = numerator % denominator;numerator = divisor;}numerator = srcclock_hz / divisor;denominator = (baudrate << 4) / divisor;/* numerator ranges from 1 ~ 7 * 64k *//* denominator ranges from 1 ~ 64k */if ((numerator > (UART_UBIR_INC_MASK * 7)) || (denominator > UART_UBIR_INC_MASK)){uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK * 7) + 1;uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;uint32_t max = m > n ? m : n;numerator /= max;denominator /= max;if (0 == numerator){numerator = 1;}if (0 == denominator){denominator = 1;}}divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;switch (divider){case 1:refFreqDiv = 0x05;break;case 2:refFreqDiv = 0x04;break;case 3:refFreqDiv = 0x03;break;case 4:refFreqDiv = 0x02;break;case 5:refFreqDiv = 0x01;break;case 6:refFreqDiv = 0x00;break;case 7:refFreqDiv = 0x06;break;default:refFreqDiv = 0x05;break;}/* Compare the difference between baudRate_Bps and calculated baud rate.* Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).* baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator / divider)/ denominator).*/tempNumerator = srcclock_hz;tempDenominator = (numerator << 4);divisor = 1;/* get the approximately maximum divisor */while (tempDenominator != 0){divisor = tempDenominator;tempDenominator = tempNumerator % tempDenominator;tempNumerator = divisor;}tempNumerator = srcclock_hz / divisor;tempDenominator = (numerator << 4) / divisor;baudDiff = (tempNumerator * denominator) / tempDenominator;baudDiff = (baudDiff >= baudrate) ? (baudDiff - baudrate) : (baudrate - baudDiff);if (baudDiff < (baudrate / 100) * 3){base->UFCR &= ~UART_UFCR_RFDIV_MASK;base->UFCR |= UART_UFCR_RFDIV(refFreqDiv);base->UBIR = UART_UBIR_INC(denominator - 1); //要先写UBIR寄存器,然后在写UBMR寄存器,3592页 base->UBMR = UART_UBMR_MOD(numerator / divider - 1);//base->ONEMS = UART_ONEMS_ONEMS(srcclock_hz / (1000 * divider));}}/** @description : 关闭指定的UART* @param - base: 要关闭的UART* @return      : 无*/
void uart_disable(UART_Type *base)
{base->UCR1 &= ~(1<<0);  
}/** @description : 打开指定的UART* @param - base: 要打开的UART* @return      : 无*/
void uart_enable(UART_Type *base)
{base->UCR1 |= (1<<0);   
}/** @description : 复位指定的UART* @param - base: 要复位的UART* @return      : 无*/
void uart_softreset(UART_Type *base)
{base->UCR2 &= ~(1<<0);          /* UCR2的bit0为0,复位UART       */while((base->UCR2 & 0x1) == 0); /* 等待复位完成                   */
}/** @description : 发送一个字符* @param - c   : 要发送的字符* @return      : 无*/
void putc(unsigned char c)
{while(((UART1->USR2 >> 3) &0X01) == 0);/* 等待上一次发送完成 */UART1->UTXD = c & 0XFF;                 /* 发送数据 */
}/** @description : 发送一个字符串* @param - str : 要发送的字符串* @return      : 无*/
void puts(char *str)
{char *p = str;while(*p)putc(*p++);
}/** @description : 接收一个字符* @param       : 无* @return      : 接收到的字符*/
unsigned char getc(void)
{while((UART1->USR2 & 0x1) == 0);/* 等待接收完成 */return UART1->URXD;             /* 返回接收到的数据 */
}/** @description : 防止编译器报错* @param       : 无* @return      : 无*/
void raise(int sig_nr) 
{}

//main.c

#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "stdio.h"/** @description : main函数* @param       : 无* @return      : 无*/
int main(void)
{unsigned char state = OFF;int a , b;int_init();                 /* 初始化中断(一定要最先调用!) */imx6u_clkinit();            /* 初始化系统时钟          */delay_init();               /* 初始化延时            */clk_enable();               /* 使能所有的时钟          */led_init();                 /* 初始化led           */beep_init();                /* 初始化beep          */uart_init();                /* 初始化串口,波特率115200 */while(1)                    {   printf("输入两个整数,使用空格隔开:");scanf("%d %d", &a, &b);                         /* 输入两个整数 */printf("\r\n数据%d + %d = %d\r\n\r\n", a, b, a+b);    /* 输出两个数相加的和 */state = !state;led_switch(LED0,state);}return 0;
}

//Makefile
修改 Makefile 中的 TARGET 为 printf,在 INCDIRS 中加入“stdio/include”,在 SRCDIRS中加入“stdio/lib”,修改后的 Makefile 如下:

CROSS_COMPILE   ?= arm-linux-gnueabihf-
TARGET          ?= printfCC              := $(CROSS_COMPILE)gcc
LD              := $(CROSS_COMPILE)ld
OBJCOPY         := $(CROSS_COMPILE)objcopy
OBJDUMP         := $(CROSS_COMPILE)objdumpLIBPATH         := -lgcc -L /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4INCDIRS         := imx6ul \stdio/include \bsp/clk \bsp/led \bsp/delay  \bsp/beep \bsp/gpio \bsp/key \bsp/exit \bsp/int \bsp/epittimer \bsp/keyfilter \bsp/uart SRCDIRS         := project \stdio/lib \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/gpio \bsp/key \bsp/exit \bsp/int \bsp/epittimer \bsp/keyfilter \bsp/uart INCLUDE         := $(patsubst %, -I %, $(INCDIRS))SFILES          := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES          := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))SFILENDIR       := $(notdir  $(SFILES))
CFILENDIR       := $(notdir  $(CFILES))SOBJS           := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS           := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS            := $(SOBJS) $(COBJS)VPATH           := $(SRCDIRS).PHONY: clean$(TARGET).bin : $(OBJS)$(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(LIBPATH)$(OBJCOPY) -O binary -S $(TARGET).elf $@$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis$(SOBJS) : obj/%.o : %.S$(CC) -Wall -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<$(COBJS) : obj/%.o : %.c$(CC) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<clean:rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

第 2 行修改变量 TARGET 为“printf”,也就是目标名称为“printf”。
第 7 行在变量 INCDIRS 中添加 stdio 相关头文件(.h)路径。第 28 行在变量 SRCDIRS 中添加 stdio 相关文件(.c)路径。
第 37 行在编译 C 文件的时候添加了选项“-Wa,-mimplicit-it=thumb”,否则的话会有如下类似的错误提示:
thumb conditional instruction should be in IT block – `addcs r5,r5,#65536’链接脚本保持不变。

在这里插入图片描述

3. 效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/894265.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验八 JSP访问数据库

实验八 JSP访问数据库 目的&#xff1a; 1、熟悉JDBC的数据库访问模式。 2、掌握使用My SQL数据库的使用 实验要求&#xff1a; 1、通过JDBC访问mysql数据&#xff0c;实现增删改查功能的实现 2、要求提交实验报告&#xff0c;将代码和实验结果页面截图放入报告中 实验过程&a…

python学opencv|读取图像(四十六)使用cv2.bitwise_or()函数实现图像按位或运算

【0】基础定义 按位与运算&#xff1a;全1取1&#xff0c;其余取0。按位或运算&#xff1a;全0取0&#xff0c;其余取1。 【1】引言 前序学习进程中&#xff0c;已经对图像按位与计算进行了详细探究&#xff0c;相关文章链接如下&#xff1a; python学opencv|读取图像&…

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置&#xff0c;输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字&#xff0c;用于区分8.打开…

基于云计算、大数据与YOLO设计的火灾/火焰目标检测

摘要&#xff1a;本研究针对火灾早期预警检测需求&#xff0c;采用在Kaggle平台获取数据、采用云计算部署的方式&#xff0c;以YOLOv11构建模型&#xff0c;使用云计算服务器训练模型。经训练&#xff0c;box loss从约3.5降至1.0&#xff0c;cls loss从约4.0降至1.0&#xff0c…

计算机毕业设计Python+CNN卷积神经网络考研院校推荐系统 考研分数线预测 考研推荐系统 考研爬虫 考研大数据 Hadoop 大数据毕设 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

小程序-基础加强-自定义组件

前言 这次讲自定义组件 1. 准备今天要用到的项目 2. 初步创建并使用自定义组件 这样就成功在home中引入了test组件 在json中引用了这个组件才能用这个组件 现在我们来实现全局引用组件 在app.json这样使用就可以了 3. 自定义组件的样式 发现页面里面的文本和组件里面的文…

docker安装emqx

emqx安装 拉取emqx镜像 docker pull emqx/emqx:v4.1.0 运行docker容器 docker run -tid --name emqx -p 1883:1883 -p 8083:8083 -p 8081:8081 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx:v4.1.0 放行端口 1、如果要是自己的虚拟机&#xff0c;并且关闭了防火墙&a…

【4Day创客实践入门教程】Day4 迈向高手之路——进一步学习!

Day4 迈向高手之路——进一步学习&#xff01; 目录 Day4 迈向高手之路——进一步学习&#xff01;更多的开发板外壳制作 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4…

深度学习之“缺失数据处理”

缺失值检测 缺失数据就是我们没有的数据。如果数据集是由向量表示的特征组成&#xff0c;那么缺失值可能表现为某些样本的一个或多个特征因为某些原因而没有测量的值。通常情况下&#xff0c;缺失值由特殊的编码方式。如果正常值都是正数&#xff0c;那么缺失值可能被标记为-1…

日志收集Day007

1.配置ES集群TLS认证: (1)elk101节点生成证书文件 cd /usr/share/elasticsearch ./bin/elasticsearch-certutil cert -out config/elastic-certificates.p12 -pass "" --days 3650 (2)elk101节点为证书文件修改属主和属组 chown elasticsearch:elasticsearch con…

arm-linux-gnueabihf安装

Linaro Releases windows下打开wsl2中的ubuntu&#xff0c;资源管理器中输入&#xff1a; \\wsl$gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz 复制到/home/ark01/tool 在 Ubuntu 中创建目录&#xff1a; /usr/local/arm&#xff0c;命令如下&#xff1a; …

LabVIEW透镜多参数自动检测系统

在现代制造业中&#xff0c;提升产品质量检测的自动化水平是提高生产效率和准确性的关键。本文介绍了一个基于LabVIEW的透镜多参数自动检测系统&#xff0c;该系统能够在单一工位上完成透镜的多项质量参数检测&#xff0c;并实现透镜的自动搬运与分选&#xff0c;极大地提升了检…

【算法】动态规划专题① ——线性DP python

目录 引入简单实现稍加变形举一反三实战演练总结 引入 楼梯有个台阶&#xff0c;每次可以一步上1阶或2阶。一共有多少种不同的上楼方法&#xff1f; 怎么去思考&#xff1f; 假设就只有1个台阶&#xff0c;走法只有&#xff1a;1 只有2台阶&#xff1a; 11&#xff0c;2 只有3台…

C++11(中)

新增默认成员函数 C11之前&#xff0c;默认成员函数有六个&#xff0c;构造函数&#xff0c;析构函数&#xff0c;拷贝构造&#xff0c;拷贝赋值重载&#xff0c;取地址重载&#xff0c;const 取地址重载。 C11增加了 移动构造 和 移动赋值重载 如果类没有实现移动构造&…

强化学习笔记——4策略迭代、值迭代、TD算法

基于策略迭代的贝尔曼方程和基于值迭代的贝尔曼方程&#xff0c;关系还是不太理解 首先梳理一下&#xff1a; 通过贝尔曼方程将强化学习转化为值迭代和策略迭代两种问题 求解上述两种贝尔曼方程有三种方法&#xff1a;DP&#xff08;有模型&#xff09;&#xff0c;MC&#xff…

计算机网络 笔记 网络层 3

IPv6 IPv6 是互联网协议第 6 版&#xff08;Internet Protocol Version 6&#xff09;的缩写&#xff0c;它是下一代互联网协议&#xff0c;旨在解决 IPv4 面临的一些问题&#xff0c;以下是关于 IPv6 的详细介绍&#xff1a; 产生背景&#xff1a; 随着互联网的迅速发展&…

【搜索回溯算法篇】:拓宽算法视野--BFS如何解决拓扑排序问题

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;搜索回溯算法篇–CSDN博客 文章目录 一.广度优先搜索&#xff08;BFS&#xff09;解决拓扑排…

23.Word:小王-制作公司战略规划文档❗【5】

目录 NO1.2.3.4 NO5.6​ NO7.8.9​ NO10.11​ NO12​ NO13.14 NO1.2.3.4 布局→页面设置对话框→纸张&#xff1a;纸张大小&#xff1a;宽度/高度→页边距&#xff1a;上下左右→版式&#xff1a;页眉页脚→文档网格&#xff1a;勾选只指定行网格✔→ 每页&#xff1a;…

视频脚本生成器(基于openai API和streamlit)

utils.py&#xff1a; # 所有和ai交互的代码放进utils.py里&#xff08;utils 通常是 “utilities” 的缩写&#xff0c;意为 “实用工具” 或 “实用函数”&#xff09;from langchain.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from lan…

Android --- CameraX讲解

预备知识 surface surfaceView SurfaceHolder surface 是什么&#xff1f; 一句话来说&#xff1a; surface是一块用于填充图像数据的内存。 surfaceView 是什么&#xff1f; 它是一个显示surface 的View。 在app中仍在 ViewHierachy 中&#xff0c;但在wms 中可以理解为…