嵌入式课程设计报告

更新时间:2024-07-05 06:35:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

数 字 时 钟

课 程 设 计 报 告

课程设计名称:系 别:姓 名:班 级:学 号:成 绩:指 导 教 师 :开 课 时 间 : 数 字 时 钟 系 _ _

_

2015-2016 学年 二 学期

目 录

一.引言 .................................................................................................................................... 1

1.1系统背景 ...................................................................................................................... 1 1.2 系统功能 ..................................................................................................................... 1 二.系统总体方案 .................................................................................................................... 2

2.1MKL25Z128VLK4微控制器介绍 ................................................................ 2 2.2系统硬件框图 .......................................................................................................... 2 三.系统硬件设计 ............................................................................................................... 3

3.1定时器(TPM)模块 ............................................................................................ 3

3.1.1计时器/定时器的工作原理 ............................................................................. 3 3.1.2 TPM模块功能概述 ........................................................................................... 3 3.2 串行通信(UART)模块 ......................................................................................... 4

3.2.1串行通信RS-232总线标准 ............................................................................. 4 3.2.2MAX232芯片进行电平转换基本原理 ............................................................... 4 3.3液晶显示模块 .............................................................................................................. 5 3.4单片机(MCU)模块 .................................................................................................... 7

3.4.1 MC9S08AW60单片机性能概述 ......................................................................... 7

四.软件设置 ............................................................................................................................ 8

4.1主函数(main.c) ...................................................................................................... 8 4.2中断子程序(isr.c) .............................................................................................. 10 4.3LCD子程序(lcd.c) .................................................................................................... 12 4.4定时器(timer.c) .................................................................................................. 15 4.5 定时器/脉宽调制子程序(tpm.c) ....................................................................... 16 4.7运行结果 .................................................................................................................... 28 五.总结 .................................................................................................................................. 28 参考文献 .................................................................................................................................. 29

一.引言

1.1系统背景

电子钟在工业控制和日常生活中是很重要的,它不仅可以用于计时、提醒又可用于对机器的控制,在自动化的过程中必然有电子钟的参与,因此电子钟的应用会越来越广泛。而且向着精确、低功耗、多功能发展。基于单片机设计的数字钟精确度较高, 因为在程序的执行过程中, 任何指令都不影响定时器的正常计数,即便程序很长也不会影响中断的时间。从而,使数字钟的精度仅仅取决于单片机的产生机器周期电路和定时器硬件电路的精确度。另外,程序较为简洁,具有可靠性和较好的可读性。如果我们想将它应用于实时控制之中,只要对上述程序和硬件电路稍加修改,便可以得到实时控制的实用系统,从而应用到实际工作与生产中去。

数字时钟系统可采用数字电路实现,也可以采用单片机来完成。若用数字电路完成,所设计的电路相当复杂,大概需要十几片数字集成块,其功能也主要依赖于数字电路的各功能模块的组合来实现,焊接的过程比较复杂,成本也非常高。若用单片机来设计制作完成,由于其功能的实现主要通过软件编程来完成,那么就降低了硬件电路的复杂性,而且其成本也有所降低数字钟是采用数字电路实现对时,分,秒,数字显示的计时装置,由于数字集成电路的发展和石英晶体振荡器的广泛应用,使得数字钟的精度,远远超过老式钟表,钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表的报时功能。数字钟已成为人们日常生活中的必需品,广泛应用于家庭、车站、码头、剧院、办公室等场所,给人们的生活、学习、工作带来极大的方便[4]。不仅如此,在现代化的进程中,也离不开电子钟的相关功能和原理,比如机械手的控制、家务的自动化、定时自动报警、按时自动打铃、时间程序自动控制、定时广播、自动起闭路灯、定时开关烘箱、通断动力设备、甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。而且是控制的核心部分。 1.2 系统功能

本次课程设计的主要任务是设计一个时钟计数器,也就是要做一个秒表,能够计数,并且按照我们平时的时间计数格式显示,当我们按下某个计数按键时候,这个计数系统就一秒一秒的计数,当计数到59秒就进位,显示分钟的部分加1,当计数分钟的数字显示到59,同样要进位,这时候时钟部分加1,如此循环下去。当我们再次按下此按键时候,计数器暂停计数,此时显示器也就暂停在那个时候不再计数了,并且显示当前计数时间。LCD 显示器要求每显示一次就刷新一次,或者刷新频率更高些。

1

二.系统总体方案

2.1MKL25Z128VLK4微控制器介绍

飞思卡尔在2010年飞思卡尔技术论坛(FTF2010)美国站推出了Kinetis系列微控制器。面向领域不同,Kinetis系列基于ARM Cortex-M内核陆续推出了Kinetis K系列、L系列、M系列、W系列。目标应用领域是智能电表、传感器控制网络、工业控制、数据采集等。

本课程设计使用MKL25Z128VLK4微控制器,它是Kinetis L 系列,其CPU核是Cortex-M0+处理器,Kinetis L系列命名格式为:

Q KL## A FFF R T PP CC (N) M KL25 Z 128 V LK 4

MCU的硬件最小系统是指可以使内部程序运行所必须的最低规模的外围电路,也可以包括写入器接口电路。一般情况下,MCU的硬件最小系统由电源、晶振及复位等电路组成。随着Flash存储器制造技术的发展,硬件最小系统把写入器的接口电路也包含在其中。 2.2系统硬件框图

KL系列MCU是以AMBA总线规范为架构SOC。一般来说,AMBA架构包含高性能系统总线 和低速、低功耗的外设总线。 系统总线AHB是负责连接ARM内核、DMA 控制器、片内存储器或其他需要高带宽的模块。外设总线APB则是用来连接系统的外围慢速模块,其协议规则相对系统总线AHB来说较为简单,它与系统总线AHB之间则通过总线桥(Bus bridge)相连,期望能減少系统总线的负载.

图2.2 KL系列MCU体系结构图

2

三.系统硬件设计

3.1定时器(TPM)模块 3.1.1计时器/定时器的工作原理

实现计数与定时的基本方法有三种:完全硬件方式、完全软件方式、可编程计数器/定时器。完全硬件方式使用数字逻辑电路实现,即完全用硬件电路实现计数/定时功能,缺点:通用性差、灵活性差。完全软件方式通过编程,利用计算机执行指令的时间实现定时,优点:节省硬件;缺点:降低了CPU的使用效率、不容易提供多作业环境,可作为实现粗略延时的方法。可编程计数器/定时器的优点:其计数/定时功能可由程序灵活地设置,设定之后与CPU并行地工作,不占用CPU的工作时间。 3.1.2 TPM模块功能概述

TPM(定时器/脉宽调制模块)共有三个模块TPM0/TPM1/TPM2,TPM0有6个通道,TPM1和TPM2只有2个通道。TPM支持输入捕捉、输出比较,并且能够产生PWM信号来控制电机。TPM的基本定时器部分是一个递增的计数器,通过设定模块的溢出值,当计数器递增到该数值时,产生TPM中断,可以通过选择时钟源和溢出值设定该计数器的频率。 1.外部引脚

TPM模块具有基本定时、输入捕捉、输出比较、脉宽调制(PWM)功能。 2.基本结构 1)计数时钟源与分频

TPM的时钟由SIM_SOPT2[TPMSRC]和SIM_SOPT2[PLLFLLSEL]来进行选择。 选择的时钟源的分频因子由状态和控制(TPMx_SC)的PS[2:0]位决定。 2)计数器

TPM具有一个16位计数器,有两种操作模式:上升计数和可逆计数。

上升计数:当(CPWMS = 0)时,上升计数被选中。0值被加载到TPM计数器中,并且计数器增量直到达到MOD中的值,此刻计数器被重载为0。

可逆计数:当(CPWMS = 1)时,可逆计数被选中。当配置为可逆计数时, MOD必须大于等于2。0值被加载到TPM计数器,并且计数器增量直到达到MOD值,此时计数器减量直到它返回0值并且可逆计数重启。

将MCU的串口与PC机相连,TPM每达到1s进行一次计时,并通过串口将计时信息发送给PC机。通过串口调试工具,可以看到时间计数值在递增。TPM模块具有中断使能、初始化、关

3

闭操作以及TPM中断处理函数。按照构件的思想,可将它们封装成独立的功能函数。 3.2 串行通信(UART)模块

实现异步串行通信功能的模块在一部分MCU中被称为通用异步收发器(Universal Asynchronous Receiver/Transmitters,UART),在另一些MCU中被称为串行通信接口(Serial Communication Interface,SCI)。 3.2.1串行通信RS-232总线标准

在MCU中,若用RS-232总线进行串行通信,则需外界电路实现电平转换,在发送端需要用驱动电平将TTL电平转换成RS-232电平;在接收端,需要用接收电路将RS-232电平转换为TTL电平。电平转换器不仅可以由晶振管分立元件构成,也可以直接使用集成电路。目前使用MAX232芯片比较多,该芯片使用单一+5V电源供电实现电平转换,下图芯片MAX232的引脚说明:

(1)VCC(16脚):正电源端,一般为+5V; (2)GND(15脚):接地;

(3)Vs+(2脚):vs+=2vcc-1.5v=8.5v; (4)Vs-(6脚):vs-=-2vcc-1.5v=-11.5v; (5)C2+,C2-(4,5脚):一般接1uF的电解电容;

(6)C1+,C2-(1,3脚):一般接1uF的电解电容。 3.2.1 MAX232 3.2.2MAX232芯片进行电平转换基本原理

MAX232芯片进行电平转换的基本原理发送过程:MCU的TxD(TTL电平)经过MAX232的11脚(T1IN)送到MAX232内部,在内部TTL电平被“提升”为232电平,通过14脚(T1OUT)发送出去。接收过程:外部232电平经过MAX232的13脚(R1IN)送入到MAX232的内部,在内部的电平被“降低”为TTL电平,经过12脚(R1OUT)送到MCU的RxD,进入MCU内部。进行MCU的串行通信接口编程时,只针对MCU的发送与接收引脚,与MAX232无关,MAX232只是起到电平转换作用。输入输出引脚分两组,基本含义如表2.2所示。在实际使用时,若只需要一路串行通信接口,可以使用其中任何一组。

4

表2 MAX232芯片输入输出引脚分类与基本接法

组别 1 TTL电平引脚 11 12 输入 输出 接MCU的TxD 接MCU的RxD 2 10 9 3.3液晶显示模块 1.点阵字符型LCD基本特点:

LCD作为电子信息产品的主要显示器件,相对于其他类型的显示器件来说有其自身的特点,主要包括:(1)低电压,低功耗;(1)平板型结构;(3)使用寿命长;(4)被动显示;(5)显示信息量大且易于彩色化;(6)无电磁辐射。

点阵字符型LCD是专门用于显示数字,字母,图形符号及少量自定义符号的液晶显示器。这类显示器把LCD控制器,点阵驱动器,字符存储器,显示体及少量的阻容元件等集成一个液晶显示模板。鉴于字符型液晶显示模块目前在国际上已经规范化,其电特性及接口特性是统一的,只要设计出一种型号的接口电路,在指令上稍加修改即可使用各种规格的字符型液晶显示器模块。点阵字符型液晶显示器模块的控制器大多数为日立公司生产的HD44780及其兼容的控制电路,如:SED1278(SEIKO EPSON),KS0066(SAMSUNG),NJU6408(NER JAPANRADIO)等。

2.字符型液晶显示器模块的特点如下:

(1)液晶显示屏是以若干5*8或5*11点阵块等组成的显示字符群。每个点阵块块为一个字符位,字符间距和行间距都是一个点的宽度。

(2)主控制电路为HD44780(HITACHI)及 其他公司的兼容电路。从程序员的角度来看LCD显示接口与编程是面向HD44780的,只要了解HD44780的编程结构即可进行LCD的显示编程。 (3)内部具有字符发生器ROM,可显示192种字符。

(4)具有64字节的字符发生器RAM,可以定义8个5*8点阵字符或4个5*11的点阵字符。 (5)具有64字节的数据显示RAM,供显示器编程使用。 (6)标准接口特性,与MC9S08系列的MCU容易接口。

5

方向 典型接口 232电平引脚 13 14 方向 连接到接口,与其它设备通过232相接 输入 接MCU的TxD 输出 接MCU的RxD 8 7 连接到接口,与其它设备通过232相接

(7)模块结构紧凑,轻巧,装配容易。

(8)单+5V电源供电(宽温型需要加-7V驱动电源)。 (9)低功耗,高可靠性。

图3.3 MCU控制液晶显示接口接线图

表3 HD44780的引脚信号

6

3.4单片机(MCU)模块

3.4.1 MC9S08AW60单片机性能概述

S80是单芯片8位微控制器解决法案。MC9S08AW60/AW60/AW48/AW32/AW16是低成本高性能的8位微处理器单元(MCU)S08家族中的成员。家族中有的MCU使用增强型S08S核,且使用不同的模块,存储空间,存储器类型与封装类型。

AW60系列主要常规模块和特点:

(1)最高达40MHz的CPU工作频率和20MHz的内部总线工作频率;时钟源选项包括晶振,谐振器,外部时钟或,内部产生的时钟。

(2)相比HC08CPU指令集,S08CPU增加了BGND指令。

(3)单线后台调试模式接口:增强的断点能力,允许单一的断点设置在线调试(在片内调试模块增加了多于两个的断点)。

(4)内含32个中断/复位源;内含2KB的片内RAM;内含60KB的片内在线可编程的Flash存储器,带有 块保护和安全选项。

(5)可选的计算机正常操作(COP)复位;低电压检测与复位或中断;非法操作码检测与复位;非法地址检测与复位。

(6)ADC:多达16个通道,10个A/D转换器与动动比较功能;两个串行通信接口SCI模块与可选的13位中断;一个串行外设接口SPI模块;集成电路互联总线IIC模块运行高达100kbps的最高总线负载;8引脚键盘中断KBI模块。

(7)Timers:1个2 通道和一个6通道16位定时器/脉冲宽度调制器模块。既有输入捕获,输出比较,脉宽调制功能。AW子系列MCU的4种封装形式只是引脚数量和形式有所区别,其他方面是一致的。

7

四.软件设置

4.1主函数(main.c)

//说明见工程文件夹下的Doc文件夹内Readme.txt文件

//============================================================================

#include \包含总头文件

int main(void) {

uint_8 LCDBuffer[20]; //uint_8 * g_DispalyInit;

//1.声明主函数使用的局部变量

uint_32 remember;

//2.关总中断

enter_critical(); // 进入临界区,关中断 //3.初始化底层模块

light_init(LIGHT_PORT, LIGHT_PIN_BLUE, LIGHT_OFF); //蓝灯初始化

uart_init (UART_1,BUSCLK, 9600); //串口1初始化, 总线时钟24000Khz,波特率9600

tpm_init(TPM0,TPM_CLKSRC_PLL,1000000);//1s

LCDInit(); //LCD初始化 //4.变量赋初值

g_time[0]=00; //(1) \时分秒\缓存初始化(00:00:00) g_time[1]=00; g_time[2]=00; //g_time[3]=11; // g_time[4]=51; g_time[3]=' '; g_time[4]='Z'; g_time[5]='h'; g_time[6]='a'; g_time[7]='o';

8

g_time[8]=' '; g_time[9]='Y'; g_time[10]='u'; g_time[11]='e'; g_time[12]=' '; g_time[13]=' '; g_time[14]=' ';

//g_DispalyInit = (uint_8 *)\

remember = g_time[2]; //(2) 临时变量remember初始化 //5.开中断

uart_enable_re_int(UART_1); //启动串口1接收中断 tpm_enable_int(TPM0); //启动模块中断 init_critical(); //开总中断 // LCDShow(g_DispalyInit);

//进入主循环

//主循环开始=============================================================

for(;;) {

if (g_time[2] != remember) //判断秒钟是否发生变化 {

LCDBuffer[0]=g_time[0]/10+'0'; LCDBuffer[1]=g_time[0]+'0'; LCDBuffer[2]=':';

LCDBuffer[3]=g_time[1]/10+'0'; LCDBuffer[4]=g_time[1]+'0'; LCDBuffer[5]=':';

LCDBuffer[6]=g_time[2]/10+'0'; LCDBuffer[7]=g_time[2]+'0'; LCDBuffer[8]=g_time[3]; LCDBuffer[9]=g_time[4]; LCDBuffer[10]=g_time[5]; LCDBuffer[11]=g_time[6];

9

LCDBuffer[12]=g_time[7]; LCDBuffer[13]=g_time[8]; LCDBuffer[14]=g_time[9]; LCDBuffer[15]=g_time[10]; LCDBuffer[16]='^'; LCDBuffer[17]='_'; LCDBuffer[18]='^';

uart_sendN(UART_1,11,g_time); remember=g_time[2]; LCDShow(LCDBuffer); }

} // end_while

//主循环结束============================================================= }

return 0;

4.2中断子程序(isr.c)

#include \

//========================中断函数服务例程=============================== //串口0接收中断服务例程 void isr_uart0_re(void) {

uint_8 ch; uint_8 flag = 1;

enter_critical();

ch = uart_re1(UART_0, &flag); if (0 == flag) {

uart_send1(UART_0, ch); }

exit_critical(); }

10

//串口1接收中断服务例程 void isr_uart1_re(void) {

static uint_8 index=0; //收到的个数 uint_8 flag = 1; enter_critical();

if(index>11)index=0;//三个字节一收,时分秒 g_time[index]=uart_re1(UART_1,&flag); if(0==flag) index++;

exit_critical(); }

//串口2接收中断服务例程 void isr_uart2_re(void) {

uint_8 ch; uint_8 flag = 1;

enter_critical();

ch = uart_re1(UART_2, &flag); if (0 == flag) {

uart_send1(UART_2, ch); } exit_critical(); }

//tpm定时中断 void tpm0_isr(void) {

static uint_32 TPMCounter = 0; {

TPMCounter++;

11

//定时器溢出中断标志

if((TPM_SC_REG(TPM0_BASE_PTR) & TPM_SC_TOF_MASK) == TPM_SC_TOF_MASK)

}

BSET(TPM_SC_TOF_SHIFT,TPM_SC_REG(TPM0_BASE_PTR));//清标志位 if(TPMCounter > 100) //TPM每中断100次(即1s)闪烁一次。 { } }

TPMCounter = 0; SecAdd1(g_time);

4.3LCD子程序(lcd.c)

//=========================================================================== // 文件名称:lcd.c // 功能概要:lcd构件头文件

// 版权所有: 苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn) // 版本更新: 2013-03-17 V1.2

//=========================================================================== #include \

//lcd控制位和数据位端口及引脚号 struct GPIO LCD[11]= { };

//内部函数原型说明

extern void LCDCommand(uint_8 cmd);

//===========================================================================

12

{LCD_RS_PORT,LCD_RS}, {LCD_RW_PORT,LCD_RW}, {LCD_E_PORT,LCD_E}, {LCD_D0_PORT,LCD_D0}, {LCD_D1_PORT,LCD_D1}, {LCD_D2_PORT,LCD_D2}, {LCD_D3_PORT,LCD_D3}, {LCD_D4_PORT,LCD_D4}, {LCD_D5_PORT,LCD_D5}, {LCD_D6_PORT,LCD_D6}, {LCD_D7_PORT,LCD_D7},

//函数名称:LCDInit //函数返回:无 //参数说明:无

//功能概要:LCD初始化。

//=========================================================================== void LCDInit() {

uint_32 i = 0;

//定义数据口和控制口为输出 for(i = 0;i < 11;i++) {

gpio_init(LCD[i].gpio_port, LCD[i].gpio_pin, 1,0); }

//设置指令,RS,R/W = 00, 写指令代码 gpio_set (LCD[0].gpio_port, LCD[0].gpio_pin, 0); gpio_set (LCD[1].gpio_port, LCD[1].gpio_pin, 0);

//功能设置- //设置指令

LCDCommand(0x38); //5*7点阵模式,2行显示,8位数据总线 LCDCommand(0x08); //关显示,关光标显示,不闪烁 LCDCommand(0x01); //清屏 for (i=0; i<40000; i++)asm(\延时 LCDCommand(0x06);

LCDCommand(0x14); //光标右移一个字符位,AC自动加1 LCDCommand(0x0C); //开显示,关光标显示,不闪烁 }

//=========================================================================== //函数名称:LCDShow //函数返回:无

//参数说明:需要显示的数据 //功能概要:液晶显示data中的数据。

//=========================================================================== void LCDShow(uint_8 data[16])

13

{

uint_8 i; //LCD初始化 LCDInit();

//显示第1行16个字符

gpio_set (LCD[0].gpio_port, LCD[0].gpio_pin, 0); gpio_set (LCD[1].gpio_port, LCD[1].gpio_pin, 0); //后7位为DD RAM地址(0x00)

LCDCommand(0x80);

//写16个数据到DD RAM

gpio_set (LCD[0].gpio_port, LCD[0].gpio_pin, 1); gpio_set (LCD[1].gpio_port, LCD[1].gpio_pin, 0); //将要显示在第1行上的16个数据逐个写入DD RAM中 for (i = 0;i < 16;i++) { }

//显示第2行16个字符

gpio_set (LCD[0].gpio_port, LCD[0].gpio_pin, 0); gpio_set (LCD[1].gpio_port, LCD[1].gpio_pin, 0); //后7位为DD RAM地址(0x40)

LCDCommand(0xC0);

gpio_set (LCD[0].gpio_port, LCD[0].gpio_pin, 1); gpio_set (LCD[1].gpio_port, LCD[1].gpio_pin, 0);

//将要显示在第2行上的16个数据逐个写入DD RAM中 for (i = 16;i < 19;i++) { } }

LCDCommand(data[i]); LCDCommand(data[i]);

14

//=========================================================================== //函数名称:LCDCommand //函数返回:无

//参数说明:cmd:待执行的命令

//功能概要:执行给定的cmd命令,且延时。

//=========================================================================== void LCDCommand(uint_8 cmd) {

uint_8 i; uint_16 j; uint_8 temp;

//等待延迟防止重复调用此函数而LCD卡死 for (j=0; j<1600; j++);asm(\ //数据送到LCD的数据线上 for(i = 3;i < 11;i++) {

gpio_set (LCD[i].gpio_port, LCD[i].gpio_pin, 0); }

for(i = 3;i < 11;i++) { }

//给出E信号的下降沿(先高后低),使数据写入LCD gpio_set (LCD[2].gpio_port, LCD[2].gpio_pin, 1); for (j=0;j<25;j++) asm(\

gpio_set (LCD[2].gpio_port, LCD[2].gpio_pin, 0); }

temp = 0x01 & (cmd>>(i-3));

gpio_set (LCD[i].gpio_port, LCD[i].gpio_pin, temp);

4.4定时器(timer.c)

//=========================================================================== //文件名称:timer.c

//功能概要:时间处理软件源文件

//版权所有:苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn) //更新记录:2013-04-27 V1.0

//===========================================================================

15

#include \

//=========================================================================== //函数名称:SecAdd1 //函数返回:无

//参数说明:*p:为指向一个时分秒数组p[3]

//功能概要:秒单元+1,并处理时分单元(00:00:00-23:59:59)

//=========================================================================== void SecAdd1(uint_8 *p) {

*(p+2)+=1; //秒+1 if(*(p+2)>=60) //秒溢出 { }

*(p+2)=0; //清秒 *(p+1)+=1; //分+1 if(*(p+1)>=60) //分溢出 {

*(p+1)=0; //清分 *p+=1; //时+1 if(*p>=24) //时溢出 {

*p=0; //清时 } }

}

4.5 定时器/脉宽调制子程序(tpm.c)

//=========================================================================== //文件名称:tpm.c

//功能概要:tpm底层驱动构件源文件

//版权所有:苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn) //更新记录:2013-5-5 V2.0

//=========================================================================== #include \

//定时器模块0,1,2地址映射

const TPM_MemMapPtr TPM_ARR[]={TPM0_BASE_PTR,TPM1_BASE_PTR,TPM2_BASE_PTR};

16

//========================================================================= //函数名称:tpm_init //功能概要:初始化tpm模块. //参数说明:tpmModule:模块号:0、1、2

// clk_src_sel:时钟源选择:1:PLL/FLL(推荐)、2:晶振 // int_us:中断微秒数,中断时间间隔 //函数返回:无

//========================================================================= void tpm_init (uint_8 tpmModule,uint_8 clk_src_sel,uint_32 int_us) {

uint_32 int_ticks;

if(tpmModule>2) tpmModule=2; //防止越界值 //开启SIM时钟门

BSET(SIM_SCGC6_TPM0_SHIFT+tpmModule,SIM_SCGC6); //使能TPM时钟 //根据传入参数(时钟源、中断时间间隔),使能时钟、确定有关寄存器值 if (1==clk_src_sel) //选择PLL/FLL为TPM模块的时钟源 {

//MCGPLL/2或者MCGFLL作为时钟源

BSET(SIM_SOPT2_PLLFLLSEL_SHIFT,SIM_SOPT2); //使能PLL为时钟源

int_ticks=6*int_us; //6*int_us=(48000/8)*int_us/1000 } else {

//晶振作为时钟源

BSET(OSC_CR_ERCLKEN_SHIFT,OSC0_CR); //开启晶振输出时钟 int_ticks=int_us; //1*int_us=(8000/8)*int_us/1000 }

SIM_SOPT2 |= SIM_SOPT2_TPMSRC(clk_src_sel); //使能时钟选择 TPM_ARR[tpmModule]->CNT=0x00; //计数器清0 TPM_ARR[tpmModule]->MOD=int_ticks; //给模数寄存器赋值

//TOF写1清0,TOIE中断使能,CMOD选择每次时钟加1,PS=0x011 选择8分频; TPM_ARR[tpmModule]->SC=TPM_SC_TOF_MASK|TPM_SC_TOIE_MASK| TPM_SC_CMOD(1)|TPM_SC_PS(3); }

17

//========================================================================= //函数名称:tpm_enable_int //功能概要:使能tpm模块中断。

//参数说明:tpmModule:模块号:0、1、2 //函数返回:无

//========================================================================= void tpm_enable_int(uint_8 tpmModule) { }

//========================================================================= //函数名称:tpm_disable_int //功能概要:禁止tpm模块初始化。 //参数说明:tpmModule:模块号:0、1、2 //函数返回:无

//========================================================================= void tpm_disable_int(uint_8 tpmModule) { }

//========================================================================= //函数名称:tpm_stop

//功能概要:禁止tpm模块。 //参数说明:tpmModule:模块号:0、1、2 //函数返回:无

//========================================================================= void tpm_stop(uint_8 tpmModule) { }

TPM_ARR[tpmModule]->SC&=~TPM_SC_CMOD(3); disable_irq(tpm0_irq_no + tpmModule); enable_irq(tpm0_irq_no + tpmModule);

4.6 串口通信子程序(uart.c)

//============================================================================ //文件名称:uart.c

//功能概要:uart底层驱动构件源文件

//版权所有:苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn)

18

//更新记录:2012-11-12 V1.0

//============================================================================ #include \

//串口1、2号地址映射

const UART_MemMapPtr UART_ARR[] = {UART1_BASE_PTR, UART2_BASE_PTR};

//打开MCGIRCLK时钟

static void MCGIRCLK_OutEnable(void);

//============================================================================ //函数名称:uart_init

//功能概要:初始化uart模块 //参数说明:uartNo:串口号:UART_0、UART_1、UART_2 // sel_clk:选择串口0时钟源:MCGIRCLK (4000Khz) // MCGPLL (48000Khz) //

BUSCLK (24000khz)

// baud:波特率:300、600、1200、2400、4800、9600、19200、115200... //函数返回:无

//说明: 当参数为UART_0时,sel_clk只能选择MCGIRCLK或MCGPLL,若选择内部时钟MCGIRCLK,

//波特率需小于19200; 当参数为UART_1或是UART_2时,sel_clk只能选择BUSCLK

//============================================================================ void uart_init (uint_8 uartNo,uint_32 sel_clk,uint_32 baud_rate) {

//局部变量声明 register uint_16 sbr; uint_8 temp; uint_32 clk_Khz;

UARTLP_MemMapPtr uartch1=UART0_BASE_PTR;//声明uartch1为UARTLP_MemMapPtr结构

体类型指针

UART_MemMapPtr uartch2; //声明uartch2为UART_MemMapPtr结构体类型指针 uartch2 = UART_ARR[uartNo-1]; //获得UART1、2模块相应口基地址

//根据带入参数uartNo,给局部变量uartch1赋值

19

时钟源

if(uartNo==0) {

switch(sel_clk) {

case MCGIRCLK:

//启用并选择UART0时钟源MCGIRCLK

MCGIRCLK_OutEnable(); //启用内部快速时钟

SIM_SOPT2 |= SIM_SOPT2_UART0SRC(0x3); //UART0选择MCGIRCLK=4000Khz

break;

case MCGPLL:

SIM_SOPT2 |= SIM_SOPT2_UART0SRC(1); //UART0选择

MCGFLLCLK_khz=48000Khz时钟源

//配置串口工作模式:8位无校验模式

sbr = (uint_16)((clk_Khz*1000)/(baud_rate * 16));

20

SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; break;

default: }

//引脚复用为串口功能并启用串口模块时钟

PORTA_PCR14 = PORT_PCR_MUX(0x3); //使能UART0_TXD PORTA_PCR15 = PORT_PCR_MUX(0x3); //使能UART0_RXD SIM_SCGC4 |= SIM_SCGC4_UART0_MASK; //启动串口0时钟

//暂时关闭串口0发送与接收功能

uartch1->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK); //根据时钟源选择时钟频率 if(MCGIRCLK == sel_clk)

clk_Khz = MCGFLL_CLK_KHZ; clk_Khz = MCGPLL_CLK_KHZ; else if (MCGPLL == sel_clk)

break;

} else {

temp = UART_BDH_REG(uartch1) & ~(UART_BDH_SBR(0x1F));

UART_BDH_REG(uartch1) = temp | UART_BDH_SBR(((sbr & 0x1F00) >> 8)); UART_BDL_REG(uartch1) = (uint_8)(sbr & UART_BDL_SBR_MASK); //初始化控制寄存器、清标志位 UART0_C4 = 0x0F; UART0_C1 = 0x00; UART0_C3 = 0x00; UART0_MA1 = 0x00; UART0_MA2 = 0x00; UART0_S1 |= 0x1F; UART0_S2 |= 0xC0; //启动发送接收

uartch1->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK);

switch (uartNo) {

case UART_1:

PORTE_PCR0 = PORT_PCR_MUX(0x3); //使能UART1_TXD PORTE_PCR1 = PORT_PCR_MUX(0x3); //使能UART1_RXD SIM_SCGC4 |= SIM_SCGC4_UART1_MASK; //启动串口1时钟 break; case UART_2:

PORTE_PCR22 = PORT_PCR_MUX(0x4); //使能UART2_TXD PORTE_PCR23 = PORT_PCR_MUX(0x4); //使能UART2_RXD SIM_SCGC4 |= SIM_SCGC4_UART2_MASK;//启动串口2时钟 break; default:

//暂时关闭串口1、2发送与接收功能

uartch2->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);

21

break; //传参错误,返回

}

}

}

//配置波特率,KL25串口1、2时钟频率只能使用 Bus clock = 24M 总线时钟 //配置串口工作模式,8位无校验模式 uartch2->C1 = 0;

sbr = (uint_16)((BUS_CLK_KHZ*1000)/(baud_rate * 16)); temp = UART_BDH_REG(uartch2) & ~(UART_BDH_SBR(0x1F));

UART_BDH_REG(uartch2) = temp | UART_BDH_SBR(((sbr & 0x1F00) >> 8)); UART_BDL_REG(uartch2) = (uint_8)(sbr & UART_BDL_SBR_MASK);

//初始化控制寄存器、清标志位 uartch2->C1 = 0x00; uartch2->C3 = 0x00; uartch2->S1 = 0x1F;

uartch2->S2 = 0x00; //启动发送接收

uartch2->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK);

//============================================================================

//函数名称:uart_send1

//参数说明:uartNo: 串口号:UART_0、UART_1、UART_2 // ch:要发送的字节

//函数返回:函数执行状态:0=正常;非0=异常。 //功能概要:串行发送1个字节

//============================================================================

uint_8 uart_send1(uint_8 uartNo, uint_8 ch) {

uint_32 t;

UARTLP_MemMapPtr uartch1=UART0_BASE_PTR; UART_MemMapPtr uartch2 = UART_ARR[uartNo-1];

for (t = 0; t < 0xFBBB; t++) {

//判断发送缓冲区是否为空

if(0==uartNo)

22

{ } else { }

if ( (uartch2->S1) & UART_S1_TDRE_MASK ) { }

uartch2->D = ch; break;

if ( (uartch1->S1) & UART_S1_TDRE_MASK ) { }

uartch1->D = ch; break;

}//end for if (t >= 0xFBBB) return 1; //发送超时 else

return 0; //成功发送 }

//============================================================================ //函数名称:uart_sendN

//参数说明:uartNo: 串口号:UART_0、UART_1、UART_2 // buff: 发送缓冲区 // len:发送长度

//函数返回: 函数执行状态:0=正常;1=异常 //功能概要:串行 接收n个字节

//============================================================================ uint_8 uart_sendN (uint_8 uartNo ,uint_16 len ,uint_8* buff) {

uint_16 i;

for (i = 0; i < len; i++) {

23

if (uart_send1(uartNo, buff[i]))

{

break; }

}

if (i >= len) return 1; else return 0; }

//============================================================================ //函数名称:uart_send_string

//参数说明:uartNo:UART模块号:UART_0、UART_1、UART_2 // buff:要发送的字符串的首地址 //函数返回: 函数执行状态:0=正常;非0=异常。 //功能概要:从指定UART端口发送一个以'\\0'结束的字符串

//============================================================================ uint_8 uart_send_string(uint_8 uartNo, void *buff) {

uint_16 i = 0;

uint_8 *buff_ptr = (uint_8 *)buff; for(i = 0; buff_ptr[i] != '\\0'; i++) {

if (uart_send1(uartNo,buff_ptr[i])) return 1; } return 0; }

//============================================================================ //函数名称:uart_re1

//参数说明:uartNo: 串口号:UART_0、UART_1、UART_2

// fp:接收成功标志的指针:*fp=0,成功接收;*fp=1,接收失败 //函数返回:接收返回字节 //功能概要:串行接收1个字节

//============================================================================

24

uint_8 uart_re1 (uint_8 uartNo,uint_8 *fp) {

uint_32 t; uint_8 dat;

for (t = 0; t < 0xFBBB; t++)//查询指定次数 {

if(0==uartNo) {

UARTLP_MemMapPtr uartch1=UART0_BASE_PTR; UART_MemMapPtr uartch2 = UART_ARR[uartNo-1];

//判断接收缓冲区是否满

if ((uartch1->S1) & UART_S1_RDRF_MASK ) {

dat = uartch1->D; *fp= 0; //收到数据 break; }

} else {

//判断接收缓冲区是否满

if ((uartch2->S1) & UART_S1_RDRF_MASK ) {

dat = uartch2->D; *fp= 0; //收到数据 break; }

}//end for if(t >= 0xFBBB) {

dat = 0xFF;

*fp = 1; //未收到数据 }

return dat; //返回接收到的数据

}

25

}

//============================================================================ //函数名称:uart_reN

//参数说明:uartNo: 串口号:UART_0、UART_1、UART_2 // buff: 接收缓冲区 // len:接收长度

//函数返回:函数执行状态 0=正常;非0=异常 //功能概要:串行 接收n个字节

//============================================================================ uint_8 uart_reN (uint_8 uartNo ,uint_16 len ,uint_8* buff) {

uint_16 i; uint_8 flag = 0;

for (i = 0; i < len && 0 == flag; i++) {

buff[i] = uart_re1(uartNo, &flag); }

if (i >= len)

return 1; //接收失败 else

return 0; //接收成功 }

//====定义串口IRQ号对应表==== static uint_8 table_irq_uart[3] = {12, 13, 14};

//============================================================================ //函数名称:uart_enable_re_int

//参数说明:uartNo: 串口号:UART_0、UART_1、UART_2 //函数返回:无

//功能概要:开串口接收中断

//============================================================================ void uart_enable_re_int(uint_8 uartNo) {

26

UARTLP_MemMapPtr uartch1=UART0_BASE_PTR;

UART_MemMapPtr uartch2 = UART_ARR[uartNo-1]; if(0==uartNo)

uartch1->C2 |= UART_C2_RIE_MASK; //开放UART接收中断 else

uartch2->C2 |= UART_C2_RIE_MASK; //开放UART接收中断 enable_irq(table_irq_uart[uartNo]); //开中断控制器IRQ中断 }

//============================================================================ //函数名称:uart_disable_re_int

//参数说明:uartNo: 串口号 :UART_0、UART_1、UART_2 //函数返回:无

//功能概要:关串口接收中断

//============================================================================ void uart_disable_re_int(uint_8 uartNo) {

UARTLP_MemMapPtr uartch1=UART0_BASE_PTR; UART_MemMapPtr uartch2 = UART_ARR[uartNo-1]; if(0==uartNo)

uartch1->C2 &= ~UART_C2_RIE_MASK; //禁止UART接收中断

else

uartch2->C2 &= ~UART_C2_RIE_MASK; //禁止UART接收中断 }

//============================================================================ //启用MCGIRCLK时钟,输出时钟频率在31.25Khz ~ 4Mhz void MCGIRCLK_OutEnable(void) {

MCG_C1 |= MCG_C1_IRCLKEN_MASK|MCG_C1_IREFSTEN_MASK; MCG_SC |=MCG_SC_FCRDIV(0x0); //内部4M快速参考时钟分频因子, //可将时钟分频在31.25Khz ~ 4Mhz MCG_C4 |= MCG_C4_FCTRIM(0xA); MCG_C2 |= MCG_C2_IRCS_MASK; while (!(MCG_S & MCG_S_IRCST_MASK));

27

disable_irq(table_irq_uart[uartNo]); //禁止中断控制器IRQ中断

}

4.7运行结果

五.总结

在老师的教导下,通过一周的学习基本懂得了数字时钟的原理和设计,通过这次的设计使我认识到本人对单片机方面的知识知道的太少了,对于书本上的很多知识还不能灵活运用,尤其是对程序设计语句的理解和运用,不够充分。在这过程中我也遇到了很多问题,比如有的程序看不懂,我就上网查资料,一句一句的看懂了程序的大致内容。最后,在电脑上进行运行,当单片机LED显示屏出现实验结果时,我的心情是无比激动的

本次的设计使我从中学到了一些很重要的东西,那就是如何从理论到实践的转化,怎样将我所学到的知识运用到我以后的工作中去。在大学的课堂的学习只是在给我们灌输专业知识,而我们应把所学的用到我们现实的生活中去,此次的数字时钟设计给我奠定了一个实践基础,我会在以后的学习、生活中磨练自己,使自己适应于以后的竞争,同时在查找资料的过程中我也学到了许多新的知识,在和同学协作过程中增进同学间的友谊,使我对团队精神的积极性和重要性有了更加充分的理解。

最后,感谢老师对我的细心的指导,正是由于老师的细心的辅导,使得我的课程设计能

28

够顺利的完成。谢谢!

参考文献

[1]《微机原理及接口技术实验指导书》,张国安,福建工程学院校内讲义,2010 [2]《单片机原理及应用》,丁元杰著,北京航空航天大学出版社,2005.8

[3]《单片机控制技术在通信中的应用-MCS-51系列》,潘超群著,电子工业出版社,2007 [4]《单片机使用教程》,李勋、刘源著,北京航空航天大学出版社,2006 [5]《综合课程设计汇编》,重庆大学出版社

29

本文来源:https://www.bwwdw.com/article/upq.html

Top