教程示例:嵌入式软件移植 printf
在嵌入式中printf 这种功能强大的函数可谓是c语言库函数的中的一股清流!也就是太好用了吧!今天分享的例程有 stm32f4ZG 和 cc2530f256,这个两款芯片的移植例程和移植教程!相信你看完后也可以移植到别的芯片去!
- 使用的keil版本为:5.21a
- IAR for 8051 version 为 10.10.1
可能会因为有些版本不同配置就略有所不同!(f4)串口1:
(f4)串口2:
下面这个是TI 的cc2530(就先跑着寄存器版本的吧,协议栈里头配置差不太多!):
为啥要移植呢!相信学过实时操作系统的都有所了解,有个叫互斥信号量的东西!就是为了防止同一时间内有两个寄存器(那十来个寄存器,不是指外设!)在访问同一块内存!这个很严重的,可能会导致程序死机,或者卡在了某个死循环里面!
我们所使用的 printf 就是首先通过 vsprinf 对我们传进来的参数进行格式化,我们传进去多少数据,他按照我们传进来的格式,格式化后统统存放在一个buf里,如果我们定义了重定向,它就会把这个buf发送至你要发送的地方!
想象一下,如果在某个系统中有一个线程在vsprintf里面运行,突然有一个任务级别比他高的任务把它运行的时间抢了过去!而任务优先级高的任务也在printf里面使用了那个buf,那就会产生上述的问题!
那就意味着我们所使用的 printf 存在不安全问题!当然我们在系统中可以通过临界保护区来处理,也可以通过信号量等等处理!
但是目前有一个线程安全
的函数,摆在你面前,就问你用不用?
那我们的上边 printf_u1 它是怎么处理的呢?毫无疑问,看代码就能知道,它是直接发送的,也就是说你传进来的每一个参数它都会顺手就发送出去(当然要看你配置),它的数据将不会存放在一个 buf 里边,在发送。这就是他给力的地方了!
keil移植printf
首先,我们到文章的末尾获取到源代码后,打开 keil 软件, 点击 project > Options for…
就能打开一下页面:
点击 C/C++,选择c99标准。到此为止编译器配置完毕!
下面来配置代码部分,打开头文件为printf.h:
1,添加这个两个文件的路径还有头文件,如果不懂可以搜搜!2,点击图片上面的printf_ 去它定义的地方,我们要做出一定的修改。
来到这里之后我们可以看到_vsprintf 这个代码里面最复杂的就是这一串函数了!
//我们只需要关心第一个参数即可!它是一个函数指针
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
//指向了一个参数为下图的函数,返回值为void
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
我们只要修改这_putchar 里面的内容即可。参数二是我加上去的为了区分不同的串口类型,有多少个串口就的写多少个_out_char 这样的函数(这个是我的方法):
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
{(void)buffer; (void)idx; (void)maxlen;if (character) {_putchar(character,1);}
}
上图是串口1的。再来看看串口2的:
int printf_u2(const char* format, ...)
{va_list va;va_start(va, format);char buffer[1];const int ret = _vsnprintf(u2_out_char, buffer, (size_t)-1, format, va);va_end(va);return ret;
}
//注意vsprintf第一参数
static inline void u2_out_char(char character, void* buffer, size_t idx, size_t maxlen)
{(void)buffer; (void)idx; (void)maxlen;if (character) {_putchar(character,2);}
}
而_putchar 就是我们数据最终流向的地方了!我是这样写的。
void _putchar(char character,char sw)
{// send char to console etc.if(sw == 1){while((USART1->SR&0X40)==0);//循环发送,直到发送完毕USART1->DR = (u8) character;}if(sw == 2){while((USART2->SR&0X40)==0);//循环发送,直到发送完毕USART2->DR = (u8) character;}if(sw == 3){while((USART3->SR&0X40)==0);//循环发送,直到发送完毕USART3->DR = (u8) character;}
}
这个 USART3->DR 为stm32串口的寄存器!读者可参照自己的芯片来配置!
简单就完了!
资料直通车:Linux内核源码技术学习路线+视频教程内核源码
学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈
IAR 配置方法
首先添加文件:
我在这里起名字为 C_Library。然后在添加文件:
选择 printf.c (反正就是添加这个文件,放到哪里看你自己):
接着就是添加编译器头文件路径:
在选择第一个大框框右边的那个:
点击Click to add。选择头文件路径所在的文件夹后 select,接着就会回到这里:
上面是配置头文件路径的,第一个是绝对路径,也就是说你工程文件移动了,就回到不到了,第二个是相对路径!选第二个吧!接着编译就会发现报错了!!!不要慌!我们首先选择Options > General Options:
此时在编译一次,就会发现也还是错了!说什么没定义。经研究,哦,原来是stdint.h这个头文件在for 8051 这款工具上,没有定义64为的无符号整形,那个怎么办啊!经发现,哦 ,原来注释这个宏就行!
程序编译通过!printf_u0 和stm32 配置类型,无非就是修改一下数据的流向!读者自己研究一下吧!!
教程示例:嵌入式软件移植 printf相关推荐
- 乐鑫代理启明云端分享:用ESP32单片机控制LED教程示例
提示:准备好开发板和LED灯 1.可以选择启明云端推出的ESP32开发板,上手简单 原因: 启明云端WT-ESP32-DevKitC V4开发板,这是一款基于ESP32的小型开发板,集WIFI+蓝牙方 ...
- java泛型方法 通配符_Java泛型教程–示例类,接口,方法,通配符等
java泛型方法 通配符 泛型是Java编程的核心功能之一,它是Java 5中引入的.如果您使用的是Java Collections ,并且版本5或更高版本,则可以肯定使用了它. 将泛型与集合类一起使 ...
- Java泛型教程–示例类,接口,方法,通配符等
泛型是Java编程的核心功能之一,它是Java 5中引入的.如果您使用的是Java Collections ,并且版本5或更高版本,则可以肯定使用了它. 在集合类中使用泛型非常容易,但是它提供了比仅创 ...
- SkyWalking--告警--使用/教程/示例
原文网址:SkyWalking--告警--使用/教程_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍SkyWalking的告警功能的用法. SkyWalking支持WebHook.gRPC.微 ...
- maven--profile--使用/教程/示例
原文网址:maven--profile--使用/教程/示例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用示例说明maven的profile的使用. mavan的profile作 ...
- Jackson--使用/教程/示例
原文网址:Jackson--使用/教程/示例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文用实例介绍Jackson的使用. 项目中我们经常会用到JSON,比如:将JSON字符串反 ...
- Angular官网教程示例知识点总结
Angular官网教程示例知识点总结 1.背景 2.知识点 2.1 应用的外壳 2.1.1 使用 Angular CLI 创建初始的应用结构 2.1.2 启动应用服务器 2.1.3 双花括号表达式 2 ...
- 教程示例:控制存储空间和文件夹的访问权限
本教程示例详细演示了如何控制用户对 OSS 存储空间和文件夹的访问.在示例中,我们首先创建一个存储空间和文件夹,然后使用阿里云主账号创建访问管理 (RAM) 用户,并为这些用户授予对所创建 OSS 存 ...
- SkyWalking--OAL--使用/教程/示例
原文网址:SkyWalking--OAL--使用/教程/示例_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍SkyWalking的OAL语法的用法. 官网 OAL介绍 http ...
最新文章
- 零基础学python爬虫-我是如何零基础开始能写Python爬虫的
- Java线程池--ThreadPoolExecutor
- 设置让php能够以root权限来执行exec() 或者 shell_exec()
- 枚举法 之Java实现凑硬币
- 打印机可以打印不能扫描怎么弄_为什么打印机可以通过电脑打印可不能扫描呢...
- Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGB
- mysql用supervisor管理_使用Supervisor管理进程
- 大V怒怼银行服务太差,一怒取走500万现金!上海银行回应了
- c++访问私有(private)成员变量的常用方法
- 机器学习笔记(十九):逻辑回归
- 数据结构——线性链表/单链表设计
- 网络安全等级符合三级等保要求套餐
- windows 键盘快捷键
- CRM系统更换服务器,CRM系统三种常见安装实施解决方式
- transition动画无效 iphone6
- 【Linux】常用配置文件路径
- 军事ar虚拟现实电子沙盘系统的功能
- Excel电子表格隔行自动填充底色
- (37)DWD 层(业务数据)
- 怎么选择适合自己的SDWAN部署方案
热门文章
- 浮动广告(页面中一张广告图片不断的变化位置)
- 华东交通大学c语言程序设计,2016年华东交通大学理学院C语言程序设计考研复试题库...
- QGC的ScreenToolsController
- 软件介绍 CamStudio (屏幕录制工具)
- 黎明杀机一直无法连接在线服务器,黎明杀机无法连接-崩坏3IOS无法连接服务器...
- OceanBase-安装
- Pylint 常见问题文档
- 【免费送书】小白也能学会的Webpack 应用瘦身技巧
- Python Smbus库简介
- LaTeX: Missing } or { inserted. ^^I\For