文章目录

  • 01 - 作业所在路径
  • 02 - 作业描述
    • 2.1 - 作业1
    • 2.2 - 作业2
  • 03 - 作业解答
    • 3.1 - 作业1解答
    • 3.2 - 作业2解答
  • 04 - 作业源码分享

01 - 作业所在路径

  ARM裸机1期加强版\源码文档图片\文档图片\第011课_串口(UART)的使用

02 - 作业描述

2.1 - 作业1

  putchar在没有读到数据时会一直死等,实现一个putchar_nowait函数, 有串口数据就读出来,没有串口数据就立刻返回错误

2.2 - 作业2

  printf函数是把输出信息直接从串口输出了,有时候我们要得到这些信息,比如后面的LCD程序中,想在LCD上显示这些信息时,就要先得到这些信息再一次性的输出到LCD。实现这个函数:int snprintf(char *str, size_t size, const char *format, …);它会把输出信息先保存在str里。(提示: printf函数中最终使用__out_putchar进行打印,你也许可以修改它,把字符保存在str中。)

03 - 作业解答

3.1 - 作业1解答

putchar在没有读到数据时会一直死等,实现一个putchar_nowait()函数, 有串口数据就读出来,没有串口数据就立刻返回错误

  添加一个时间变量,在while中一直递减就可以粗略实现(UART_RREADY_WIDTH和UART_TEMPTY_BIT是自己写的宏,和老师的数值是一样的)

#修改前,阻塞等待
int putchar(int c)
{while(!(UTRSTAT0&(UART_TEMPTY_WIDTH<<UART_TEMPTY_BIT)));UTXH0 = (unsigned char)c;return 0;
}
#修改后,等待一小段时间
int putchar_nowait(void)
{unsigned int time = 1000000;unsigned char val;//在time时间下读数据while(!(UTRSTAT0&(UART_RREADY_WIDTH<<UART_RREADY_BIT)) && --time);if(time){val = URXH0;while(!(UTRSTAT0&(UART_TEMPTY_WIDTH<<UART_TEMPTY_BIT)));UTXH0 = (unsigned char)val;return 1;}elsereturn 0;
}

3.2 - 作业2解答

printf函数是把输出信息直接从串口输出了,有时候我们要得到这些信息,比如后面的LCD程序中,想在LCD上显示这些信息时,就要先得到这些信息再一次性的输出到LCD。实现这个函数:int snprintf(char *str, size_t size, const char *format, …);它会把输出信息先保存在str里。(提示: printf函数中最终使用__out_putchar进行打印,你也许可以修改它,把字符保存在str中。)

  基本思想是原本输出到串口的内容都输出到str,其实改动比较大,几乎所有函数都要加上一个char* str的参数,修改最大的是my_vprintf函数,在格式化输出的时候需要统计转换到的字符数,改变str指针位置,同时要检查是否超出长度指定的长度,需要做截断处理,代码太长,只贴出修改后的代码

uart_printf.h

#ifndef _UART_PRINTF_H_
#define _UART_PRINTF_H_//#define  __out_putchar     putchar
#define  MAX_NUMBER_BYTES   64typedef char *  va_list;
//保证4字节对齐
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//移动指针
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
//取值
#define va_arg(ap,t)    ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) )
//赋值,避免野指针
#define va_end(ap)      ( ap = (va_list)0 )int printf(const char *format, ...);
int snprintf(char *str, int size, const char *format, ...);
void printf_test(void);#endif

uart_printf.c

#include "uart_printf.h"
#include "uart.h"unsigned char hex_tab[]= {'0','1','2','3','4','5','6','7',\'8','9','a','b','c','d','e','f'};/*** @brief  把一个字符输出到str* @param  c:待输出的字符* @param  str:待输出的缓冲区* @retval 返回0*/
void __out_putchar(char *str,unsigned char c)
{*str = c;return ;
}
/*** @brief  输出一个字符到str中* @param  c:待输出的字符* @param  str:待输出的缓冲区* @retval 返回0*/
static int outc(char *str,int c)
{__out_putchar(str,c);return 0;
}/*** @brief  输出一个字符串到str中* @param  s:待输出的字符串* @retval 返回输出的字符数*/
static int outs(char *str, const char *s)
{int ret = 0;while (*s != '\0'){__out_putchar(str++,*s++);ret++;}return ret;
}/*** @brief  利用串口输出一个数字* @param  n       :待输出的数字* @param  base  :代表进制,8进制/10进制/16进制* @param  lead   :前导码* @param  maxwidth:在一行中输出的最大字符数* @retval 返回输出的字符数*/
static int out_num(char *str,long n, int base,char lead,int maxwidth)
{unsigned long m=0;char buf[MAX_NUMBER_BYTES];char *s = buf + sizeof(buf);int count=0,i=0;*--s = '\0';if (n < 0){m = -n;}else{m = n;}do{*--s = hex_tab[m%base];count++;}while ((m /= base) != 0);if( maxwidth && count < maxwidth){for (i=maxwidth - count; i; i--)*--s = lead;}if (n < 0)*--s = '-';return outs(str,s);
}/*** @brief  在ap中按照fmt格式输出size长度的一个字符串到str中* @param  fmt     :待输出字符串的格式字符串* @param  ap      :待输出的数据缓冲区头指针* @param  size    :共输出的字节数* @param  str      :输出的缓冲区* @retval 返回0*/
static int my_vprintf(char *str,int size,const char *fmt, va_list ap)
{char lead=' ';int  maxwidth=0;int s = 0;for(; *fmt != '\0'; fmt++){if (*fmt != '%'){if(++s <= size){outc(str++,*fmt);continue;}elsebreak;}//format : %08d, %8d,%d,%u,%x,%f,%c,%sfmt++;if(*fmt == '0'){lead = '0';fmt++;}lead=' ';maxwidth=0;while(*fmt >= '0' && *fmt <= '9'){maxwidth *=10;maxwidth += (*fmt - '0');fmt++;}int len;switch (*fmt){case 'd':len = out_num(str,va_arg(ap, int),          10,lead,maxwidth);break;case 'o':len = out_num(str,va_arg(ap, unsigned int),  8,lead,maxwidth);break;case 'u':len = out_num(str,va_arg(ap, unsigned int), 10,lead,maxwidth);break;case 'x':len = out_num(str,va_arg(ap, unsigned int), 16,lead,maxwidth);break;case 'c':if(++s <= size)outc(str++,va_arg(ap, int   ));break;case 's':len = outs(str,va_arg(ap, char *));break;default:if(++s <= size)outc(str++,*fmt);break;}//检查输入的字符串是否超出长度if(len<= (size-s)){str+=len;s+=len;}else{*(str+size) = '\0';s = size+1;}}return 0;
}/*** @brief  模仿sprint函数,按照format格式,把数据输入到str中* @param  str         :缓存* @param  size      :缓存的字节数* @param  format        :数据格式* @param  ...);       :0个或者多个参数* @retval 返回输出的字符数*/
int snprintf(char *str, int size, const char *format, ...)
{va_list ap;//得到数据缓冲区首地址va_start(ap, format);//根据格式+数据进行输出到strmy_vprintf(str, size, format, ap);//指针赋值,避免野指针va_end(ap);return 0;
}

04 - 作业源码分享

百度网盘 提取码:wkcp

韦东山ARM第一期作业(二)UART串口相关推荐

  1. 韦东山ARM第一期作业(三)内存控制器和SDRAM

    文章目录 01 - 作业所在路径 02 - 作业描述 03 - 作业解答 01 - 作业所在路径   ARM裸机1期加强版\源码文档图片\文档图片\第012课_内存控制器与SDRAM 02 - 作业描 ...

  2. 韦东山ARM第一期作业(一)ARM时钟体系

    文章目录 01 - 作业所在路径 02 - 作业描述 03 - 作业解答 01 - 作业所在路径   ARM裸机1期加强版\源码文档图片\文档图片\第010课_掌握ARM芯片时钟体系 02 - 作业描 ...

  3. 韦东山ARM第一期总结

    文章目录 01 - 裸机开发特点 1.1 - 51 / Arduino / STM等单片机 1.2 - ARM单片机 02 - 总结 一切都站在裸机开发者的角度而言 01 - 裸机开发特点 1.1 - ...

  4. 韦东山嵌入式第一期学习笔记DAY_4——8_3编写第1个程序点亮LED

    作者:GWD 时间:2019.7.5 一.课程内容: 1.不太完美的配置方式(会破坏寄存器其他的位) 2.问:几条常用的ARM汇编指令? 3.问:LDR与MOVE的区别? 答:LDR时伪指令,执行的时 ...

  5. 韦东山嵌入式第一期学习笔记DAY_1——2_0_安装ubuntu16.04虚拟机

    作者:GWD 时间:2019.7.2 一. 课程内容: 1. 简单介绍linux: 1).linux内核与linux发行版本的联系: 2. 安装ubuntu虚拟机: 二. 学习要点: 1. 问:SCM ...

  6. 韦东山嵌入式第一期学习笔记DAY_3——7_1_裸机开发步骤简介

    作者:GWD 时间:2019.7.4 一.课程内容: 1.问:windows.linux与arm(linux)建立工程的区别? 答: 2.问:ubuntu环境下编译一个C文件的过程? 答: 1).建立 ...

  7. 韦东山嵌入式第一期学习笔记DAY_1——3_1_linux命令入门演示

    作者:GWD 时间:2019.7.2 一.课程内容: 1.问:除了图形界面,ubuntu下面有没有其他方式也可以创建目录.创建文件? 答:通过linux命令,linux命令,是每一个linux学习者必 ...

  8. 韦东山嵌入式第一期学习笔记DAY_1——3_2_shell命令解析器功能说明

    作者:GWD 时间:2019.7.2 一. 课程内容: 1.问:在shell(命令解释器)中输入字符串并回车的过程 答: 1). shell根据第1个字符串去环境变量PATH所指定的目录中找到同名的应 ...

  9. 韦东山嵌入式第一期学习笔记DAY_2——6_2_使用eop烧写裸板程序

    作者:GWD 时间:2019.7.3 一.课程内容 1.安装JTAG驱动: 1).复制驱动所在路径: 2).安装驱动时候,选择浏览计算机以查找(注意对于EOP需要安装几次驱动,路径都是一样的) 2.安 ...

最新文章

  1. tab选项卡在鼠标经过时实现切换延迟
  2. java juc包多线程编程案例:Executor入门示例
  3. java中组合_java中组合模式详解和使用方法
  4. bios设置 联想m8000t_Ideapad 700-17笔记本使用bios设置u盘启动方法介绍【图文详解】...
  5. php fpm 日志记录,使用Nginx在PHP-FPM 7上启用错误日志记录?
  6. 【渝粤题库】陕西师范大学292231 财务管理Ⅱ 作业(专升本)
  7. java dns 缓存_一次排查多线程引发Java DNS缓存的Bug
  8. Fiddler中文版安装及使用
  9. adb命令刷机vivox20_刷机常用adb命令及刷recovery脚本
  10. 拖动或点击CMD窗口造成程序阻塞,在bat文件中关闭cmd窗口的快速编辑模式
  11. 计算机丢失MSVCR100.dll文件的解决办法
  12. 食品经营许可证模板_食品流通许可证与食品经营许可证
  13. 设计word模板添加书签
  14. 如何计算ROI(一)
  15. 计算机硬盘硬盘共享如何设置,两台电脑如何共享文件夹?Win10设置共享文件夹或共享磁盘的方法...
  16. 四种基础博弈 巴什博奕+威佐夫博奕+斐波那契博弈+K倍博弈
  17. 郑州大学本科生毕业论文latex模板
  18. 【数据分析】【MySQL】快速入门+案例+代码+命令整理+GIF实操演示
  19. 【正则表达式】从字符串中提取数字
  20. python 云服务器 网站

热门文章

  1. Cilium Hubble
  2. FPGA笔记2——跨时钟域同步信号方法
  3. [论文复现]演化博弈方法用于多智能体系统最优资源分配
  4. 微信一直无妨链接服务器,微信被拉黑了?没关系!这波操作你必须掌握!
  5. sicily 6445. Triangle transformation
  6. 出了新iPhone终于治好了我的选择恐惧症
  7. oracle中split的使用方法,Oracle 自定义split 函数实例详解
  8. 探索与创新:低代码助力金融数字化转型发展
  9. [论文速读]:全景相机(360度相机)室内图像的景深估计 Depth Estimation for Indoors Spherical Panoramas (三篇)
  10. input加progress组合写进度条的简单音乐播放器实现