华清远见嵌入式系统实训报告
(2017—2018学年第一学期)
姓 名: ****** 专业班级: ************ 学 号: ************** 学 院: 电气工程与自动化学院 带队教师: 乔美英,胡伟
2017年9月25日
河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告
华清远见嵌入式系统实训报告
一、 实习时间
2017.9.25--2017.9.29
9月25日(周一)上午 9月25日(周一)下午 9月26日(周二)上午 9月26日(周二)下午 9月27日(周三)上午 9月27日(周三)下午 9月28日(周四)上午 实习动员与项目介绍 Keil安装及新建工程 LED点灯与esc按键 PWM蜂鸣器 Timer定时器和WDT定时器 SysTick定时器 OLED显示屏及ADC电压转换 9月28日(周四)下午 9月29日(周五)上午 9月29日(周五)下午
1
光线传感器实验 温湿度采集实验 项目整合及验收 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告
二、 实习的性质、目的
2.1 实习性质
虽然嵌入式系统是近几年才开始真正风靡起来的,但事实上嵌入式这个概念却很早就已经存在了。从上个世纪70年代单片机的出现到今天各种嵌入式微处理器、微控制器的广泛应用,嵌入式系统少说也有了近30年的历史。
从嵌入式系统的构成上看,嵌入式系统是集软硬件于一体的、可工作的计算机系统。从外观上看,嵌入式系统像是一个“可编程”的电子“器件”从功能上看。它是对宿主对象进行控制,使其具有“智能”的控制器。从应用的角度看,嵌入式系统与通用计算机系统相比,有如下一些特点:
(1)专用性强 由于嵌入式系统通常是面向某个特定应用的,所以嵌入式系统的硬件和软件,尤其是软件,都是为特定用户群来设计的,它通常都具有某种专用性的特点。
(2)实时性好 目前,嵌入式系统广泛应用于生产过程控制、数据采集、传输通信等场合,主要用来对宿主对象进行控制。所以都对嵌入式系统有或多或少的实时性。例如,对嵌入在武器装各中的嵌入式系统、在火箭中的嵌入式系统、一些工业控制装置中的控制系统等应用中的实时性要求就极高。也正因为这种要求,在硬件上嵌入式系统极少使用存取速度慢的磁盘等存储器。在软件上更是加以精心设计,从而可使嵌入式系统快速地响应外部事件。当然,随着嵌入式系统应用的扩展,有些系统对实时性要求也并不是很高,例如近年来发展速度比较快的手持式计算机、掌上电脑等。但总体来说,实时性是对嵌入式系统的普遍要求,是设计者和用户重点考虑的一个重要指标。
(3)可裁剪性好 从嵌入式系统专用性的特点来看,作为嵌入式系统的供应者,理应提供各式各样的硬件和软件以各选用。但是,这样做势必会提高产品的成本。为了既不提高成本,又满足专用性的需要,嵌入式系统的供应者必须采取相应措施使产品在通用和专用之间进行某种平衡。目前的做法是把嵌人式系统硬件和操作系统设计成可裁剪的,以便使嵌入式系统开发人员根据实际应用需要来量体裁衣,去除冗余,从而使系统在满足应用要求的前提下达到最精简的配置。
(4)可靠性高 由于有些嵌入式系统所承担的计算任务涉及产品质量、人身设备安全、等重大事务,加之有些嵌入式系统的宿主对象要工作在无人值守的场合。例如危险性高的工业环境中、内嵌有嵌入式系统的仪器仪中、在人际罕至的气象检测系统中以及为侦察敌方行动的小型智能装置中等。所以与普通系统相比较,对嵌入式系 统可靠性的要求极高。
(5)功耗低 有很多嵌入式系统的宿主对象都是一些小型应用系统。例如移动电话、PDA、 MP3、飞机、舰船、数码相机等。这些设备不可能配各容量较大的电源,因此低功耗一直是嵌入式系统最求的目标。当然也是为了降低系统的功耗,嵌入式系统中的软件一般不存储于磁盘等载体中,而都固化在存储器芯片或单片系统的存储器之中。
2
河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告
这个是我们实习用到的恩智浦公司的一款开发板,其芯片采用Cortex-M0处理器。
2.2 实习目的
学习和了解了嵌入式在生活中的重要作用和发展过程,熟练掌握ARM硬件体系结构,熟悉NXP LPC11C14下的嵌入式编程流程,积累自己的软件编写经验。能够参与并实现一个真实和完整的嵌入式项目,为今后的学习和将从事的技术工作打下坚实的基础 。
1、复习与巩固C语言编程基础,熟练使用keil软件及其编程环境。
2、学习嵌入式系统,将书本上的知识与实际相结合,通过真实的实训,巩固书本知道,以达到可以运用的目的。 3、学习将各个学科的知识融合运用的技能,通过培训,增强自己的计算机技术、动手实践能力,以及计算机开发等一定的实际技术。
4、通过实训可以提前了解当前市场需求,以及社会需要的人才类型,以便可以为自己的以后就业方向做出一个较为客观的导向。
3
河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告
三、 实习内容
3.1 实习动员与项目介绍(9月25日上午)
今天上午主要就是老师与我们互相认识了一下,活跃一下气氛,然后规划了未来一周的实习内容,好让我们有所准备。知道学习的大致方向。
3.2 Keil安装及新建工程(9月25日下午)
3.2.1 软件安装
1. 打开从计算机下载或者从其他计算机上Copy过来的文件夹,选择setup安装程序。
2. 在接下来的提示框中选择FULL(完全版)点击安装。 3. 在提示框中输入程序序列号。
4. 选择disk(钥匙盘) ——其地址在安装文件夹的其他文件当中,可手动搜索找到。
5. 点击完成,结束安装过程
4
河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告
3.2.2新建工程
1. 点击“project>New Projecy…”菜单,出现一个对话框,要求给将要建立的工程起一个名字,在编辑框中那个输入一个名字,不需要扩展,点击 保存。 2. 选择目标器件,我们使用的是选择nxp>lpc11c14,点击确定回到主界面。 3. 在工程窗口的文件页中,出现了“Target1”,前面有+号,点击+号展开,可以看到下一层是“Source Groupl”,这是的工程还是一个空的工程,里面什么文件都没有,需要动手把写好的源程序加入 。
4. 点击Source Groupl使用其反白显示,然后点击鼠标右键,出现一个下拉菜单,加入刚刚编辑好的源程序。
5
河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告
3.3 LED点灯与esc按键实验(9月26日上午)
程序源码及注释:
#include int main(void) { led1_init(); //led灯初始化 sw_init(); //按键初始化 while(1) { if(!sw_status()) { delay(10); //延迟函数 led1_change(); //改变led的状态 delay(100); //延迟函数 led1_close(); //关闭led灯 delay(100); } } } 6 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 上图为led与芯片连接图,只需配置所需寄存器即可。GPIO 数据寄存器和GPIO 数据方向寄存器。 Led初始化步骤: 1.选择IO功能:配置IOCON【2:0】 = 0 2.将PI03_0引脚设置为输出:DIR[0] = 1 3.开灯:DATA[0] = 0 3.4 PWM蜂鸣器实验(9月26日下午) 程序源码及注释: #include void buzzer_open(int pwm) { LPC_IOCON->R_PIO1_1 = 0X3; LPC_SYSCON->SYSAHBCLKCTRL |= 1<<10; LPC_SYSCON->SYSAHBCLKCTRL |= 1<<16; LPC_TMR32B1->PR = 0X7F; LPC_TMR32B1->MR0 = pwm; LPC_TMR32B1->MR3 = 1500; LPC_TMR32B1->MCR |= 1<<10; LPC_TMR32B1->PWMC |= 1; LPC_TMR32B1->PWMC |= 1<<3; LPC_TMR32B1->TCR |= 1; } int main() { 7 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 } while(1) { buzzer_open(750); } 3.5 Timer定时器和WDT定时器(9月27日上午) 实验名称:timer定时器实现呼吸灯 实验目的:掌握定时器的定时中断用法 实验步骤: 1.初始化LED1 void led1_init(void) { (1)I/O配置(选择GPIO功能) (2)GPIO数据方向选择(输入/输出功能) } 2.完成定时器中断处理函数 void TIMER32_0_IRQHandler(void) { (1)判断是不是由定时器定时产生的中断 LPC_TMR32B0->IR[0] = 0 (2)是的话就切换LED灯状态 led1_change(); (3)清除timer中断(为下一次产生中断准备) LPC_TMR32B0->IR = 1;(写1清0) } 8 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 4.初始化配置32bit的timer0,实现定时间隔为1S(每隔1S产生一次定时器中断) void timer32B0_init(void) { (1)使能定时器0时钟 LPC_SYSCON->SYSAHBCLKCTRL[9] = 1 (2)定时器中断间隔设置(这里使用的是MR0输出通道) LPC_TMR32B0->MR0 = 12000000-1; (定时时间为1S) (3)匹配寄存器 = TC(计数器)时,采取的方式为:产生中断 LPC_TMR32B0->MCR[0] = 1; //产生中断 LPC_TMR32B0->MCR[1] = 1; //循环产生中断:TC清0,重新计数 (4)使能定时器中断 NVIC_EnableIRQ(TIMER_32_0_IRQn); //向core(内核)注册定时器0中断 5.设置定时器0的中断优先级 NVIC_SetPriority(TIMER_32_0_IRQn, 3); 6.使能定时器LPC_TMR32B0->TCR = 1; } 实验名称:看门狗定时器中断 实验目的:掌握看门狗定时器的用法:(1)普通定时器中断(2)复位中断 从喂狗和不喂狗的现象比较入手 实验分析: (1)看门狗定时器是SOC内部的功能模块,没有使用外设引脚 (2)看门狗定时器的实质也是一个定时器: a.要有时钟信号源 b.针对时钟信号源进行分频操作 c.定时计数:向下减计数 d.输出中断:普通中断和复位中断 e.产生中断不是通过比较,而是减到0的时候自动产生 实验步骤(如果自己的startup_LPC11xx.s中没有在main之前调用SystemInit,记得要在main函数里调用下): 1.初始化看门狗定时器 (1)系统配置(时钟源选择和使能) a.使能看门狗定时器时钟 LPC_SYSCON->SYSAHBCLKCTRL[15] = 1 b.看门狗振荡器时钟源配置 LPC_SYSCON->WDTOSCCTRL = 0x03F; //配置看门狗振荡器输出时钟频率 9 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 LPC_SYSCON->PDRUNCFG &= ~(0x1<<6); //掉电配置寄存器对看门狗振荡器上电 c.选择看门狗定时器时钟源 LPC_SYSCON->WDTCLKSEL = 0x02; //选择看门狗时钟源:看门狗振荡器 LPC_SYSCON->WDTCLKUEN = 0x01; //允许更换新的时钟源 LPC_SYSCON->WDTCLKUEN = 0x00; //使更新的时钟源生效:必须先写0后写1 LPC_SYSCON->WDTCLKUEN = 0x01; d.等待更新的时钟源正式生效 循环判断LPC_SYSCON->WDTCLKUEN[0] = 1的时候表示正式生效(在对更新时钟源生效的时候,状态位已经自动清0了) while ( !(LPC_SYSCON->WDTCLKUEN & 0x01) ); //等待时钟源正式生效 e.看门狗时钟分频 LPC_SYSCON->WDTCLKDIV = 2; (2)看门狗定时器相关配置 a.看门狗定时时间设置 LPC_WDT->TC = 0x000002FF ; //每次看门狗都是将TC中的值装载到计数器开始向下计数直到减到0,每次向TC中写的数据不能低于0xff(低于ff按ff计算) b.看门狗定时器模式设置:普通中断还是选择复位中断 普通:LPC_WDT->MOD[0] = 1(如果选择了普通中断的话就需要注册下中断:NVIC_EnableIRQ(WDT_IRQn); //使能WDT中断) 复位中断:LPC_WDT->MOD[0] = 1, LPC_WDT->MOD[1] = 1 c.使能看门狗 向FEED寄存器先写0xAA再写0x55开启定时器:因为仅仅是将MODE模式寄存器中的MOEN标志位使能是不够的 2.定时器中断处理函数 (1)写自己的处理代码:切换LED1状态,并延时500 LPC_GPIO3->DATA ^= 1<<0; mydelay(500); (2)清除超时中断标记(由于看门狗是向下减计数的,为了防止由于标记未清除,CPU误认为又产生了WDT中断) LPC_WDT->MOD &= ~(1<<2); (3)继续使能看门狗定时器 LPC_WDT->MOD[0] = 1 ; LPC_WDT->FEED = 0xAA; LPC_WDT->FEED = 0x55; 注意:使能看门狗要完成两步才行:LPC_WDT->MOD[0] = 1和对FEED寄 10 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 存器的先写0xAA再写0x55。 3.6 SysTick定时器实验(9月27日下午) 实验名称: 系统滴答定时器定时,实现精准呼吸灯 实验目的:掌握精准定时器使用:系统滴答定时器(system tick) 实验分析: (1)系统滴答定时器的实质也是定时器,通常以固定时间间隔产生系统定时中断 (2)与普通定时器对比学习: 1.没有任何外部引脚:因为没有输入捕获和输出比较 2.系统滴答定时器是由cortex-M0内部集成的一部分,他的作用是产生一个固定的10ms的中断 实验步骤: 1.滴答定时器初始化 直接调用内核提供接口SysTick_Config:SysTick_Config(48000);//定时10ms 2.中断处理函数 void SysTick_Handler(void) { static uint32_t Tick=0; Tick ++; //静态变量 if(Tick == 500) { led1_open(); //打开LED1 11 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 } else if(Tick >= 1000) { led1_close(); Tick = 0; } } //关闭LED1 3.7 OLED显示屏及ADC电压转换实验(9月28日上午) OLED基本信息 1.显示颜色:蓝色和黄色 2.像素点:128*,实际显示的时候,是先将显示的数据写到SSD对应的RAM上,也就是说这些像素点实际对应的是RAM存储空间,对RAM空间进行了划分: 行:每8个像素点为一页(8页) 列:以像素点为单位(128) 3.在OLED显示屏外设上集成的有OLED驱动芯片:SSD1306,发送数据和命令的接口有串口、I2C和SPI三种方式 4.SSD1306中有三种不同的内存地址模式:页地址模式、水平地址模式,垂直地址模式 页地址模式: 一共分成8页/行(每行占8个像素),每一页又分成了16份,每一份又 12 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 细分了16份 列数 页数 page0 0 ....... 127 page1 0 ....... 127 .... .... .... .... page7 0 ....... 127 每一页: 高4bit地址(决定行): 0 1 2 ... f 低4bit地址(决定列): 0 1 2 ... f 水平地址: 从左往右,从上往下 垂直地址: 从上往下,从左往右 5.要在OLED上显示,实际上是将数据先显示到SSD1306的显示RAM上,具体流程如下: 1.通过命令0xb0 ~ 0xb7来设置目标显示位置的页开始地址 2.通过命令0x00 ~ 0x0f来设置低开始列地址 3.通过命令0x10 ~ 0x1f来设置高开始列地址 使用方法: 1.对OLED初始化,初始化步骤参照OLED手册第4.4章节描述 2.要在OLED上显示字符或者图像,需要先将显示的具体位置发送到OLED,然后再发送实际数据 实验名称:A/D模拟数字信号转换 实验目的:掌握使用ADC模块将模拟信号转换成数字信号 实验步骤: 1.查找原理图 找到对应连接物理引脚Pioneer0_11 ADC模块特点:8路输入转化,这里使用第0个 2.ADC模块初始化 (1)I/O配置 LPC_IOCON->R_PIO0_11[2:0] = 2; //选择AD0功能 (2)ADC时钟使能 LPC_SYSCON->SYSAHBCLKCTRL[13] = 1 (3)ADC上电 LPC_SYSCON->PDRUNCFG[4] = 0;//ADC模块上电 (4)ADC控制寄存器 a.选择转换通道0 LPC_ADC->CR[0] = 1 b.时钟分频设置 13 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 LPC_ADC->CR[15:8] = 4;//AHB频率是12MHz,为了避免AD转换太快导致数据失真,所以最快转换频率不能高于4.5MHz:12000000 c.转换触发方式 LPC_ADC->CR[16] = 0 - 软件触发转换 1 - 硬件重复挨个扫描通道0-7,挨个循环转换,此时AD0INTEN[8]=0 e.每次转换需要的时间周期间隔 LPC_ADC->CR[19:17] = 0; //表示间隔11个周期转化一次 f.转换开始条件 当LPC_ADC->CR[16] = 0时有效,用软件设置ad转换的条件 LPC_ADC->CR[26:24] = 0;//不开始转换 3.读取转换数据 (1)手动开始转换 LPC_ADC->CR |= (1 << 24); (2)等待转换完成 while ( 1 ) /*等待转换完成 */ { regVal = LPC_ADC->DR[0]; if ( regVal & 0x80000000 ) { break; } } (3)关闭转换 LPC_ADC->CR &= 0xF8FFFFFF; (4)读取转换数据 ADC_Data = ( regVal >> 6 ) & 0x3FF; 得到的数据还需要转换: ADC_Data = (ADC_Data*(3.3/1023))*1000;//单位是mV 4.通过OLED显示 snprintf(buf, 13, \"ADC : %dmV \组显示电压字符串 //电压显示 OLED_DisStrLine(7, 0, (uint8_t *)buf); 14 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 3.8 光线传感器实验(9月28日下午) 实验名称:采集室内光线强度 实验目的:掌握ISL29003光线采集模块使用方法 实验分析: (1)查找原理图得到光线传感器和SOC之间的通讯方式是:IIC PIO0_4作为 ISL29003 的 SDA,PIO0_5 作为 ISL29003 的 SCL,PIO0_7 作为 ISL29003的 Light_nINT。 (2)ISL光线模块采集光线强度有四个范围: Range 1 = 0 lux to 1000 lux Range 2 = 0 lux to 4000 lux(本实验中使用这个范围) Range 3 = 0 lux to 16,000 lux Range 4 = 0 lux to ,000 lux SL29003包含两个二极管,一个为光敏二极管、一个为红外二极管,这两个二极管的光谱是相对的,二极管将光转换成电流,然后通过16位的模拟转换器ADC将电流再转换成数字并输出 (3)从ISL29003的芯片手册找到: 1)light的设备ID是1000100(2进制) 注意,在向I2C从设备发送地址的时候,高7bit是1000100,最后1bit是表示读(1)/写(0) 2)light转换的精度是16bit 3)寄存器相关地址 命令寄存器:0x00 控制寄存器:0x01 存放光照强度低有效字节寄存器:0x04 高有效字节寄存器:0x05 (4)IIC 起始和停止条件 SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况表示起始条件; SCL 线是高电平时,SDA 线由低电平向高电平切换,这个情况表示停止 15 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 条件。 起始和停止条件一般由主机产生,总线在起始条件后被认为处于忙的状态 当CLK高电平的时候,如果SDA产生下降沿,则说明数据传输开始, 在CLK为高电平的时候传输数据,首先传主机、从机的address,然后在传数据。当在CLK处于高电平的时候,如果SDA产生了上升沿,说明传输结束。 实验步骤(main函数中程序调用流程): 1.初始化I2C协议 调用I2C协议接口:I2CInit(I2CMASTER, 0);//初始化I2C配置 2.使能light传感器开始转换 void light_enable(void) { uint8_t buf[2]; buf[0] = 0x00; //命令寄存器地址 buf[1] = 1<<7; I2CWrite(0x44<<1, buf, 2); //0x44<<1指的是:0x44是light传感器ID,左移1位空出来0bit指的是写标志 } 3.设置light的光照采集范围:0~4000 void light_setRange(void) { uint8_t buf[2]; uint8_t ctrl ; //读取原来的控制寄存器值 buf[0] = 0x01; I2CWrite(0x44<<1, buf, 1); I2CRead(0x44<<1, buf, 1); ctrl = buf[0]; /*设置光线转换范围*/ ctrl &= ~(3 << 2); ctrl |= 1<<2; //设置光照采集范围4000 //将配置的结果回写到控制寄存器 buf[0] = 0xx01; buf[1] = ctrl; I2CWrite(0x44<<1, buf, 2); } 4.OLED显示屏初始化和SPI接口协议初始化 SPI_IOConfig(0); SPI_Init(0, 8, 2); OLED_Init_I(); 16 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 5.主循环 while(1) { value = light_read(); //读取light数据 snprintf(buf, 20, \"%d \ OLED_DisStrLine(2, 0, (uint8_t *)buf); //显示 mydelay(500); //自己写个延时函数 } 关于light数据读取单独封装函数实现: unsigned int light_read(void) { uint32_t data = 0; uint8_t buf[1]; buf[0] = 0x04; I2CWrite(0x44<<1, buf, 1); //发送低字节寄存器地址 I2CRead(0x44<<1, buf, 1); //读取低字节数据 data = buf[0]; //存放低byte buf[0] = 0x05; I2CWrite(0x44<<1, buf, 1); //发送高字节寄存器地址 I2CRead(0x44<<1, buf, 1); //读取高字节数据 data = (buf[0] << 8 | data); //拼凑数据 //数据转换:管线传输范围最大是32,light的精度是16bit data *= 32; data /= (1<<16); return data; } 17 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 3.9 温湿度采集实验(9月29日上午) 实验名称:检测室内温度和湿度数据 实验目的:掌握DHT11温湿度模块数据采集 实验分析: 1.目的是为了从DHT11温湿度采集模块中获取温度和湿度数据 2.DHT11温湿度采集模块信息(从DHT11模块采集得到) (1)单总线:只有一根线和SOC引脚相连 (2)温湿度数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位 (3)校验数据:8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据 = 所得结果的后8bit 本来这里采用的是异或校验:将所有数据进行按位异或,所得的结果作为第5字节(8bit),但是由于进行加法的时候,对于单个char类型数据,即使产生了进位也没有关系(因为我们只能保留8bit,因此这里异或校验等价于加法) (4)SOC读取DHT11数据流程: a.SOC将引脚PIO1_5设置为输出,然后输出低电平,持续时间不低于18ms(表示起始信号) b.将PIO1_5引脚输出电平恢复到高电平释放总线(恢复高电平) c.将PIO1_5引脚切换为输入状态,接收DHT11的针对起始信号的应答(应答信号是持续时间不低于80us的低电平信号) d.接下来DHT11会发出持续时间不低于80us的高电平,通知SOC将开始传输温湿度数据 e.传输的数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位 f.DHT11发送完数据后,会继续输出持续时间50us的低电平,然后切换PIO1_5到输入状态,因为上拉电阻的存在,PIO1_5的输入状态会切换到高电平(空闲) 实验步骤: 1.从原理图中得到,DHT11和PIO1_5引脚相连 18 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 2.初始化IO:调用GPIOInit函数,注册PIO中断,接下来读取DHT11数据的时候会用到 GPIOInit(); // GPIO时钟和中断使能 3.systick定时器初始化 SysTick_Config(50000); //定时时间为1ms,因为后续关于DHT11的时序很多的间隔都是 补全systick的中断处理函数,虽然不用,但是一定要写,不然会导致程序运行卡死,显示屏不出画面 void SysTick_Handler(void) { //空函数,什么都不用写 } 4.PIO1_5引脚中断处理函数:这是为了在对DHT11进行数据读取的时候,判断引脚信号变化 void PIOINT1_IRQHandler(void) { (1)判断产生中断是不是PIO1_5,PIO1组引脚不止5号引脚这一根,如果成立才继续向下执行 if(GPIOIntStatus(PORT1, 5)) (2)读取当前系统定时器的计数器数值,用来作为DHT11读数据(0或1)时序时间判断 p3_2_tc = SysTick->VAL; //读取当前系统定时器的计数器数值 (3)是否进入引脚中断标志 p3_2_counter++; //全局变量产生变化 (4)清除PIO1_5引脚中断痕迹 GPIOIntClear(PORT1, 5); } 5.读取DHT11温湿度数据函数 //temp:输出参数,用来存放读到的温度数据(temp[2],在main函数中定义) //hum:输出参数,用来存放读取到的湿度数据(hum[2],在main函数汇总定义) //返回值:数据读取成功返回1,失败返回0 uint32_t Read_Temp_Hum(uint8_t *temp, uint8_t *hum) { uint32_t cnt_last; //用来区分是否产生PIO1_5中断 uint8_t hum_10, hum_01, temp_10, temp_01, chksum, chk;//存放从DHT11读取到的数据信息 uint32_t tc1, tc; //统计systick定时器的时间 uint32_t i; 19 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 //刚开始初始化下两个变量之间关系 p3_2_counter = 0; cnt_last = p3_2_counter; GPIOIntDisable(PORT1, 5); //先禁止PIO1_5产生中断 //输出开始信号:低电平,持续时间不能小于18us GPIOSetDir(PORT1, 5, 1); //设置PIO1_5引脚为输出功能 GPIOSetValue(PORT1, 5, 0); delay_ms(30); GPIOSetValue(PORT1, 5, 1); //输出高电平,恢复空闲 //等待DHT11的应答 GPIOSetDir(PORT1, 5, 0); //设置设置为输入,DHT11会输出80us的低电平作为应答,紧接着输出80us的高电平通知芯片开始接收数据 //使能中断,捕捉IO引脚下降沿中断,因为DHT11的应答信号是低电平,所以会产生下降沿,当产生下降沿的时候会触发PIO1_5中断 GPIOSetInterrupt(PORT1, 5, 0, 0, 0); //设置PIO1_5中断类型:边沿触发,单边沿,下降沿 GPIOIntEnable(PORT1, 5);//注册使能 //循环判断:下降沿(应答开始),上升沿(数据传输开始),下降沿(数据传输结束) for(i=0; i<3; i++) //接收DHT11发送来的80us的应答和80us的开始接收数据信号:先判断下降沿,然后判断上升沿,最后判断下降沿 { GPIOSetInterrupt(PORT1, 5, 0, 0, i&0x01); while(p3_2_counter == cnt_last); //遇到下降沿 cnt_last = p3_2_counter; } //数据读取:0-50us低电平+26-28us高电平,1-50us低电平+70us高电平 for(i=0; i<40; i++) //循环接收40bit数据 { GPIOSetInterrupt(PORT1, 5, 0, 0, 1); //判断上升沿到来 while(p3_2_counter == cnt_last); //判断PIO1_5是否产生中断,没有就一直等 cnt_last = p3_2_counter; 20 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 tc1 = p3_2_tc; //统计下systick计数器值 GPIOSetInterrupt(PORT1, 5, 0, 0, 0); //判断下降沿到来 while(p3_2_counter == cnt_last); cnt_last = p3_2_counter; //计算停留在高电平的时间差(正好是传输高电平的时间差) if(p3_2_tc < tc1) { tc = tc1 - p3_2_tc; } else { tc = SYS_TICK_LOAD - (p3_2_tc - tc1); } if(i < 8) //第1个byte { hum_10 <<= 1; if(tc >= DHT11_DATA_0) //时间差大于70,就是数值1,否则就是0 hum_10 |= 0x01; } else if(i < 16) //第2个byte { hum_01 <<= 1; if(tc >= DHT11_DATA_0) hum_01 |= 0x01; } else if(i < 24) //第3个byte { temp_10 <<= 1; if(tc >= DHT11_DATA_0) temp_10 |= 0x01; } else if(i < 32) // 第4个byte { temp_01 <<= 1; if(tc >= DHT11_DATA_0) temp_01 |= 0x01; } else //第5个byte { 21 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 chksum <<= 1; if(tc >= DHT11_DATA_0) chksum |= 0x01; } } GPIOSetInterrupt(PORT1, 5, 0, 0, 1); //结束信号判断:上升沿到来 while(p3_2_counter == cnt_last); GPIOIntDisable(PORT1, 5); *temp = temp_10; *(temp+1) = temp_01; *hum = hum_10; *(hum+1) = hum_01; chk = hum_10; //校验计算:异或校验,看读取到的32bit是否正确 chk += hum_01; chk += temp_10; chk += temp_01; if(chk == chksum) return 1; else return 0; } 6.主函数main //1.初始化GPIO中断 GPIOInit(); //2.初始化systick定时器 //3.OLED显示屏和SPI接口初始化 //4.读取温湿度数据 while(1) { //读取温湿度数据 if(Read_Temp_Hum(temp, hum)) 为真表示成功 temp[0] = 温度整数部分 temp[1] = 温度小数部分 hum[0] = 湿度整数部分 22 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 hum[1] = 湿度小数部分 //使用OLED_DisStrLine函数分别显示温湿度数据 } (LPC11Cx2/Cx4系列芯片包含3个可靠的振荡器:系统振荡器、内部RC振荡器和看门狗振荡器) 3.10 项目整合及验收(9月29日下午) 方法: (1)定义一个菜单结构体 typedef struct { uint16_t max_numb; //菜单选项总个数 uint16_t numb; //当前选中的菜单 char *title; //子菜单标题 char *item[32]; //描述 } Menu_TypeDef; Menu_TypeDef menu; (2)初始化菜单 menu.max_numb = 5; //一共有5个子菜单 menu.numb = 1; //默认选中第一个 menu.title = \"Main\";//主菜单名:main menu.item[0] = \"1. LED\"; menu.item[1] = \"2. Speaker\"; menu.item[2] = \"3. Temp & Hum\"; menu.item[3] = \"4. Light\"; menu.item[4] = \"5. Voltage\"; (3)定义一个菜单遍历显示函数 void Dis_Menu(Menu_TypeDef menu) { uint16_t page, row, i; //定义页、行 page = (menu.numb-1) / 6; //6个子菜单为一页 i = (page+1) * 6; if(i < menu.max_numb) row = 5; else row = (menu.max_numb-1) % 6; 23 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 OLED_ClearScreen(); //清屏 //显示页码 OLED_DisStrLine(0, 0, (uint8_t *)menu.title); OLED_DisChar(0, 6*17, 0, 'P'); OLED_DisChar(0, 6*18, 0, 'g'); OLED_DisChar(0, 6*19, 0, ' '); OLED_DisChar(0, 6*20, 0, 0x30+1+page); for(i=0; i<=row; i++) //循环显示当前页 { if(menu.numb == (page*6 + i + 1)) OLED_DisStrLine(2+ i, 1, *)menu.item[page*6+i]); else OLED_DisStrLine(2+ i, 0, *)menu.item[page*6+i]); } } (4)检测五向键状态 uint16_t KEY_Read(void) { //↑键被按下 if(!GPIOGetValue(PORT1, 8)) { return 1; } //↓键被按下 if(!GPIOGetValue(PORT1, 9)) { return 2; } //←键被按下 if(!GPIOGetValue(PORT1, 10)) { return 3; } //→键被按下 if(!GPIOGetValue(PORT1, 11)) 24 (uint8_t (uint8_t 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 { return 4; } //中间确定键被按下 if(!GPIOGetValue(PORT0, 3)) { return 5; } //返回键被按下 if(!GPIOGetValue(PORT1, 4)) { return 6; } return 0; } (5)main函数的主循环中根据按键状态修改菜单当前选中项 switch(KEY_Read()) { case KEY_UP: if(menu.numb > 1) menu.numb --; else menu.numb = menu.max_numb; Dis_Menu(menu); delay_ms(150); break; case KEY_DOWN: if(menu.numb < menu.max_numb) menu.numb ++; else menu.numb = 1; Dis_Menu(menu); delay_ms(150); break; case KEY_SEL: switch(menu.numb) { 25 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 case 1: LED_Test(); break; //执行LED灯操作,点灯 case 2: Speaker_Test(); break; case 3: Temp_Hum_Test(); break; case 4: Light_Test(); break; case 5: ADC_Test(); break; default: break; } break; case KEY_ESC: Dis_Menu(menu); break; default: break; } 3.11 问题及解决方法 在这为期一周的实习中,遇到大大小小的问题已经数不过来了,但是最终经过同学以及老师的帮助,让我很好的解决掉这些问题。从刚开始连软件都不会安装一点一点学习,让我学习了不少东西。 刚开始安装软件的时候,需要改注册表,刚开始不会,在耐心看了老师的操作后自己也会了。然后就是新建工程的时候走了好多的弯路,但最后也慢慢的熟练起来。编写程序的时候刚开始写的比较乱,没有一点逻辑性,最后也会了一些技巧编写的熟练起来了。 26 河南理工大学自动化2015级卓越班华清远见嵌入式系统实训报告 四 实习总结及体会 由于初次接触嵌入式系统,感觉蛮难的,但是比较容易上手,其中遇到很多的难题,很多东西都是第一次接触。老师在旁边指导操作,加上自己去摸索练习,其中还是有一些难度。然而坚持就是胜利,牙一咬眼一闭坚持做下去,而通过本次实验,我感觉收获还是蛮多的。可能我对于嵌入式的知识学习的还是不太多,但是这之外的东西收获颇丰。它让我学会了如何通过自己的努力去认知一个新事物,更重要的是端正自己的学习态度,只有真正下功夫去学习,有了付出,才能有收获。 再者,通过本次实习,我学会了怎样看电路图并进行电路分析,以及软件的调试工作,这对我以后的工作具有非常大的作用。还学会了如何找出自己程序中的错误,继而去排除解决问题。这就是一个自我学习的过程。当我们通过实验去学习理论知识时,自己动手得出的结论不仅能加深我们对嵌入式的理解,更能加深我们对此的记忆。 我相信在以后的学习工作中,我一定会端正自己的学习态度,一丝不苟的去对待每一件事。只有做好足够的准备,才能事半功倍。 五 实习建议 通过本次在217的为期一周的嵌入式实训,我感觉这种培训形式的实训比去外面参观一些工厂好多了,这样可以学到一些课堂上学不到的但是非常重要的内容,对以后找工作很有帮助,而不是仅仅苍白地参观一些工厂,对技能的增长没有一点点帮助。所以我建议我们可以多进行一些类似这样培训形式的实习。 27
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务