您好、欢迎来到现金彩票网!
当前位置:246天天好彩正版资料大全 > 调试例程 >

跟我学OSKinetis]第4课-从启动代码开始看!UART!

发布时间:2019-07-03 09:41 来源:未知 编辑:admin

  如果大家运行过前面几节课提到的例程,就会从串口调试助手看到许多启动信息,这些信息包含了当前固件库的版本号、单片机的内核时钟等信息。但是回到例程的app代码内,我们并没有找到这些内容的输出代码,那么它们跑到哪里去了呢?虽然这些代码是固件库所包含的代码,开发者不用更改,但是本着深入理解固件库和Kinetis启动流程的学习目的,我们还是要在学习UART的同时,来看看这些代码到底是怎样运行的。

  Kinetis单片机在运行到用户的main()函数之前,还要运行一些叫做启动代码的东西来进行寄存器、中断向量表、系统时钟初始化等操作。其中我们经常看到的启动信息的输出就是在系统时钟初始化之后进行的。

  首先要找到这些启动代码在什么位置,在第2课中我们提到过,在IAR开发环境中的CPU组下包含的所有代码都是硬件相关,这里就是Kinetis启动代码的大本营了。其中startup_K60.s是单片机的汇编启动代码文件,system_MK60DZ10.c是K60的系统初始化c语言代码,可以统称为这些是Kinetis单片机的启动代码。

  在单片机的寻址空间的前1024个字节中存放着256个异常向量(exception vectors),其中我们只需要知道几个重要的即可。第一个向量是栈(Stack)指针,物理地址0×00000000;第二个向量是复位地址(Reset_Handler)指针,物理地址0×00000004;往后的所有向量都是系统中断和外设中断的地址指针了。

  这些指针地址都是在startup_K60.s汇编文件内定义的,代码如下:

  Line 2:DCD是一个汇编伪指令,就是给指定的数据分配存储单元。例如这行,指定的数据是sfe(CSTACK),给该数据分配的存储地址就是0×00000000,该地址是上面的__vector_table标号决定的。CSTACK是*.icf文件内定义的一个块,用于存放栈数据,sfe(CSTACK)代表取这个块的最后一个地址的下一个地址,为什么要取末尾的地址呢,因为栈数据是从一段空间的底部逐渐往顶部存入的,而读取是从栈顶部开始的。

  Line 3:包含此行以后的代码就是系统中断指针地址和外设中断指针地址了。

  当单片机上电或者复位后,单片机首先将CSTACK地址所存的地址指针读入到SP寄存器(堆栈指针寄存器),然后将Reset_Handler地址所存的地址指针读入到PC寄存器(程序计数寄存器),接下来单片机就会开始运行Reset_Handler地址开始处的程序代码了。代码如下:

  Line 4~5:同上,当执行完系统初始化函数后,紧接着执行用户app的main()函数,即用户自己的工程代码。

  可见,当单片机上电或复位后,单片机的启动顺序是先初始化SP、PC寄存器,接下来就开始运行PC寄存器指向地址的代码了。

  当单片机启动后,首先运行的代码就是该文件内的SystemInit()系统初始化函数。在这个函数中,系统干了这样几件事:1)时能全部IO口时钟、2)禁用看门狗、3)拷贝中断向量表和相关数据代码到RAM中、4)初始化相关总线)打印系统初始化信息。

  1)前面的时能IO口时钟是使单片机的所有IO口全部处于激活状态,如果在不先使能的状况下对相关IO口进行操作,就会触发系统硬件错误中断(HardFault_Handler)。

  2)禁用看门狗模块会方便开发调试,以防在总线初始化或者调试过程中出现系统复位状况。

  3)这一步是初学者比较难懂的部分,为什么要拷贝中断向量表、相关变量和函数到RAM中呢?大家都知道,RAM的读写速度要比ROM的读写速度快很多,而我们的中断向量表是从单片机存储空间的物理地址开头0×00000000处开始存储的,这部分属于ROM空间,为了让单片机能更快的响应中断事件,把中断向量表拷贝到RAM中运行是目前通行的做法。还有一些函数和变量也是要拷贝到RAM中的,这些变量指的是已经初始化的全局变量,函数指的是由__RAMFUNC关键字定义的函数,这些概念我们会在后面的小节中讲到。这部分用到的代码如下:

  4)这一部分的代码除了初始化各部分时钟,还包括读取各部分时钟的频率到相关全局变量内,以便固件库的其他模块进行调用。代码如下:

  Line 5:获取实际初始化后的内核频率,将频率值赋值到全局变量SystemCoreClock中。

  5)终于说到本节课的主题了——UART!这一步首先初始化输出调试信息需要用到的UART串口模块。代码如下所示:

  Line 1:这里采用宏定义DEBUG_PRINT来控制系统启动时是否输出这些调试信息。

  至此,OSKinetis固件库的启动代码就基本讲完了,一些对于初学者比较晦涩难懂的概念,我们会在后面解释,你也可以百度谷歌这些概念,看看大家的解释。例如一些汇编指令、堆栈的区别、icf链接文件的格式等等。

  UART模块是通用异步收发器的英文缩写(Universal Asynchronous Receiver/Transmitter),这是个正式的名字,还有个小名儿叫串口。串口的功能我们就不多说了,教科书、网络上的介绍多的是。它是一个非常简单的模块,上手极快,但是对于Kinetis的串口来说,它又有许多高级的功能、比如DMA传输、FIFO等等。本节课我们只讲如何用OSKinetis固件库来使用UART模块的简单收发功能,包括中断的使用。其实上面的启动代码部分已经简单涉及到了,聪明的你会发现它的初始化方式是和GPIO是一样的。

  首先看非中断发送接收的使用方法,打开例程“04-(UART)LPLD_SerialComm”,用户程序代码main()内首先调用了自定义函数uart_init()对UART进行初始化,看下其实现代码:

  Line 1:首先在函数外定义一个全局UART初始化结构体变量。思路和GPIO初始化一样。

  Line 6~7:分别配置UART的接收和发送引脚,这里的参数是由K60的复用引脚来决定的,每个串口模块有不同的发送接收复用引脚,你可以随意配置,但是如果配置了不存在的复用引脚,会初始化失败。如果你不配置这个成员变量,固件库会初始化默认的引脚。具体参数请看在线文档中对UART_InitTypeDef结构体的描述(点击查看)

  Line 8:最后调用UART初始化函数进行初始化,参数就是刚刚配置的结构体变量。

  LPLD_UART_PutCharArr(UART5, Input something:\r\n, 20);Line 1:该函数的第一个参数是选择串口号,第二个参数是字符串,即字节型数组,第三个参数是字节数组的长度。此时K60会从他的UART5的PTE8引脚输出这些信息,使用RUSH Kinetis开发板的童鞋可以直接将USB线插到开发板母板的USB接口上,通过串口调试助手查看信息。

  Line 2:调用串口发送字节函数,从串口5发送字节recv。这个函数和while循环上面的那个不一样,仅仅是发送一个字节变量。

  最终的调试结果是,当你每在串口调试助手发送一个字节,就会在接收界面收到一个同样的数据,结果如下图所示。

  这次同样是插到RUSH Kinetis开发板的串口转USB接口上,为什么没有输出启动信息呢?波特率没有设置为115200?不对,我们初始化时用的是9600。秘密就在k60_card.h代码内,原来在这个工程的配置中,我们将PRINT_ON_OFF宏定义定义为了0,这样就不会在启动时输出调试信息了!

  Line 6:设置中断接收函数为uart_isr,大家要记住,使能一个模块的中断,就必须配置相关的中断函数,否则初始化会失败或者导致硬件错误。

  Line 10:调用UART中断使能函数,使能UART5的不可屏蔽中断。

  Line 4:还是调用接收字节函数,接收一个8位字节,这里函数就不会一直停留等待了,因为是中断信号告诉我们可以接收字节了,函数内部只要直接获取数据就可以了。

  程序最终的调试结果和上一个例程是一样的,但是如果你在上面代码Line 4的位置打一个断点,就会发现,当你通过串口调试助手发送字节的时候,程序会进入这个断点。证明了串口5成功进入了接收中断。大家也可以照猫画虎,写一个发送中断的程序,发送中断是在用户发送完成一个字节后才触发中断。

  在所有例程中,我们通过串口输出调试信息都是用printf()这个函数,如果大家写过C/C++代码,那么肯定对他的用法已经很熟悉了(不知道这个函数的用法请找度娘)。但关键是,printf()是从哪个串口输出信息,波特率又是多少呢?没错,在前面的system_MK60DZ10.c一小节已经提到了,调试信息输出的串口初始化是在SystemInit()函数内进行的。你只需要更改k60_card.h代码内的TERM_PORT和TERMINAL_BAUD宏定义来更改串口号和波特率即可。那么输出引脚如何设置呢,如果你不更改SystemInit()内的代码,那么默认引脚就是在线文档中些的那些。如果你想更改其他引脚,那么按照正常的方法就可以更改,例程中已经介绍过了。

  可能有些人对第一个例程“01-LPLD_HelloWorld”中的这两个函数还抱有疑问。当时使用它们的时候也没有进行串口初始化操作啊,怎么就能输入输出字符了呢?其实这两个函数也是调用了TERM_PORT和TERMINAL_BAUD宏定义来使用UART库函数发送和接收字符,你只要查看这两个函数的定义即可发现。

  串口调试助手显示乱码问题:可能是波特率设置的与单片机的不一样,如果单片机设置为9600,而上位机设置的是115200肯定是乱码;还可能是单片机发送的是16进制数据,而串口调试助手设置的是“字符串显示”;硬件问题,很少见,除非接收和发送引脚连反了,这样的线进制数据和字符串的问题:你只要了解ASC-ii码是什么东西就好了,简单的说ASC-ii码就是字符,而每个字符都对应有一个8位的整形数字。例如“!”叹号对应的数字是33,33的16进制转化是0×21,因此当你在单片机输出一个字符“!”时,如果在串口调试助手设置为字符显示,那么显示就是“!”,如果设置为16进制显示,那么显示就是“21”。

  如果你使用RUSH Kinetis开发板、K60 Card转接板的串口转USB接口,

  来控制单片机的复位,一般的串口调试助手没有禁用DTR信号,致使DTR信号为低电平,导致单片机复位无法运行。

  « 上一篇:[跟我学OSKinetis]第3课-开始干正事吧!GPIO!

http://bayliedog.com/diaoshilicheng/492.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有