AVR单片机C语言高级程序设计(推荐9篇)
一、教材名称:<
二、课程总学时:108学时 [理论: 72 学时;实验与上机:36学时]
三、适用专业和开课学期:软件技术专业,第2学期。
四、实验的目的与任务:
《C程序设计》是一门实践性很强的课程。通过实验使学生加深对课堂讲授的概念、语法、算法、编程技术的理解;熟悉C程序设计的开发环境;掌握程序设计和调试的基本技能。并通过实践激发学生进一步学习的积极性,培养学生的学习兴趣和创新思维。通过8个实验,使学生经过一定数量的上机训练,了解和掌握C程序设计的环境、程序的数据表示、程序的执行流程控制、程序的整体结构等C程序设计的基本概念和应用技术。
五、主要仪器设备及台(套)数
安装Windowsxp,TC2.0等软件的计算机,每生一台。
六、主要实验教材(指导书)及参考用书:
谭浩强主编,《C程序设计题解与上机指导》,清华大学出版社。
七、成绩考核方式及评分标准
实验占课程总课时1/3,每项实验按该实验说明要求规定的评分标准积分,学期末合计的实验成绩占课程总成绩的18%。
八、实验开出率:100%
九、实验项目与要求
实验一:C程序的运行环境和运行一个C程序的方法(2学时)
实验性质:验证性实验
一、实验目的
1.了解所用的计算机系统的基本操作方法,学会独立使用该系统。2.了解在该系统上如何编辑、编译、连接和运行一个C程序。3.通过运行简单的C程序,初步了解C源程序的特点。
二、实验内容
1.调用编辑程序,输入教材第一章例1.1程序,并进行编译和运行。应了解所用的系统是用什么命令进行编译和连接运行的。编译和连接后所得到的目标程序的后缀是什么形式的?
2.输入并运行教材第一章中例1.2。
3.输入并运行教材第一章中例1.3,了解如何在运行时向程序变量输入数据。
实验二 数据类型、运算符和表达式(2学时)
实验性质:验证性实验
一、实验目的
1.掌握C语言数据类型,熟悉如何定义一个整型、字符型、实型变量,以及对它们赋值的方法,了解以上类型数据输出时所用格式转换符。
2.学会使用C的有关算术运算符,以及包含这些运算符的表达式,特别是自加(++)和自减(--)运算符的使用。
3.进一步熟悉C程序的编辑、编译、连接和运行的过程。
二、实验内容
1.输入并运行教材第三章例3.6.即: #include
printf(“%c %cn”,c1,c2); printf(“%d %dn”,c1,c2); } 在此基础上 ①将第二行改为: int c1,c2;再使之运行,分析结果。②再将第三行、第四行改为: c1=300;c2=400;再使之运行,分析其运行结果。
2.输入并运行教材第三章习题3.6,在上机前先用人工分析程序写出应得结果,上机后将二者对照。
3.输入并运行习题3.10。即: #include
printf(“%d,%d,%d,%d”,i,j, i++,j++);⑤程序改为: main(){int i,j,m=0,n=0;;i=8;j=10;m+=i++;n-=--j;printf(“i=%d,j=%d,m=%d,n=%d”,i,j,m,n);}
实验三 最简单的C程序设计(2学时)
实验性质:验证性实验
一、实验目的
1.掌握C语言中使用最多的一种语句—赋值语句的使用。2.掌握数据的输入输出的方法,能正确使用各种格式转换符。
二、实验内容
1.输入并运行以下程序:
#include
void main(){int a,b; float d,e; char c1,c2; double f,g; long m,n;
unsigned int p,q; a=61;b=62; c1=’a’;c2=’b’; d=3.56;e=-6.87;
f=3157.890121;g=0.123456789; m=50000;n=-60000; p=32768;q=40000;
printf(“a=%d,b=%dn c1=%c,c2=%cnd=%6.2f,e=%6.2fn”,a,b,c1,c2,d,e); printf(“f=%15.6f,g=%15.12fnm=%ld,n=%ldnp=%u,q=%un”,f,g,m,m,p,q); } 在此基础上,做以下改动: ① 将程序第8-13行改为: a=61;b=62; c1=a;c2=b;
f=3157.890121;g=0.123456789; d=f;e=g;
p=a=m=50000;q=b=n=-60000; 运行程序,分析结果。
② 在①的基础上将printf语句改为:
printf(“a=%d,b=%dn c1=%c,c2=%cnd=%15.6f,e=%15.12fn”,a,b,c1,c2,d,e);
printf(“f=%f,g=%fn m=%ld,n=%ldn p=%d,q=%dn”,f,g,m,n,p,q); 运行程序。
2.编写程序,用getchar函数读入两个字符c1、c2,然后分别用putchar函数和printf函数输出这两个字符。
上机运行程序,比较用printf和putchar函数输出字符的特点。
实验四 选择结构程序设计(2学时)
实验性质:设计性实验
一、实验目的
1.了解C语言表示逻辑量的方法(以0代表“假”,以1代表“真”); 2.学会正确使用逻辑运算符和逻辑表达式; 3.熟练掌握if语句和switch语句。
二、实验内容
先编程序,解决以下问题,然后上机调试运行程序。1.有一个函数 xy2x13x11x11x10 x10用scanf函数输入x的值(分别为x<1、1~
10、≥10三种情况),求y值。2.给出一个百分制成绩,要求输出成绩等级‘A’,‘B’,‘C’,‘D’,‘E’。90分以上为‘A’,80~89分为‘B’,70~79分为‘C’,60~69分为‘D’,60分以下为‘E’。
实验五 循环控制(4学时)
实验性质:设计性实验
一、实验目的
1.熟悉用while语句,do-while语句和for语句实现循环的方法。2.掌握在程序设计中用循环的方法实现各种算法(如穷举、迭代、递推等)。
二、实验内容
编程序并上机调试运行。
1.输入两个正整数,求其中最大公约数和最小公倍数。2.用牛顿迭代法求方程2x3-4x2+3x-6=0在1.5附近的根。
实验六 数组(4学时)
实验性质:设计性实验
一、实验目的
1.掌握一维数组和二维数组的定义、赋值和输入输出的方法; 2.掌握字符数组和字符串函数的使用。3.掌握与数组有关的算法(特别是排序算法)。
二、实验内容
编程序并上机调试运行。
1.用选择法对10个整数排序。10个整数用scanf函数输入。2.将两个字符串连接起来,不要用strcat函数。实验七 函数(4学时)
实验性质:设计性实验
一、实验目的
1.掌握定义函数的方法;
2.掌握函数实参与形参的对应关系,以及“值传递”的方式; 3.掌握函数的嵌套调用和递归调用的方法;
4.掌握全局变量和局部变量,动态变量和静态变量的概念和使用方法。
二、实验内容
编程序并上机调试运行。
1.写一个判断素数的函数,在主函数输入一个整数,输出是否是素数的信息。2.求两个整数的最大公约数和最小公倍数,用一个函数求最大公约数。用另一函数根据求出的最大公约数求最小公倍数。
(1)用全局变量的方法。将两个整数的最大公约数、最小公倍数都设为全局变量。
(2)不用全局变量,两个整数在主函数中输入,并传送给函数1,求出的最大公约数返回主函数,然后再与两个整数一起作为实参传递给函数2,以求出最小公倍数,返回到主函数输出最大公约数和最小公倍数。
实验八 预处理命令(2学时)
实验性质:设计性实验
一、实验目的
1.掌握宏定义的方法; 2.掌握文件包含处理方法; 3.掌握条件编译的方法。
二、实验内容
编程序并上机调试运行。
1.定义一个带参数的宏,使两个参数的值互换。在主函数中输入两个数作为使用宏的实参,输出已交换后的两个值。
说明:在程序主函数使用宏时只能用两个实参,如SWAP(a,b),不能用三个参数。2.用条件编译方法实现以下功能:
输入一行电报文字,可以任选两种输出,一为原文输出;一为将字母变成其下字母(如‘a’变成‘b’,„,‘z’变成‘a’。其它字符不变)。用#define命令来控制是否要译成密码。例如: #define CHANGE 1 则输出密码。若 #define CHANGE 0 则不译成密码,按原码输出。用条件编译方法来处理。
实验九 指针(4学时)
实验性质:设计性实验
一、实验目的
1.掌握指针的概念,会定义和使用指针变量; 2.学会使用数组的指针和指向数组的指针变量; 3.学会使用字符串的指针和指向字符串的指针变量; 4.学会使用指向函数的指针变量;
二、实验内容
编程序并上机调试运行程序(都要求用指针处理)。1.输入三个整数,按由小到大的顺序输出。
2.将一个3*3的矩阵转置,用一函数实现之。在主函数中用scanf函数输入以下矩阵元素:
1 7133915511 19将数组名作为函数实参。函数调用后在主函数中输出已转置的矩阵。3.用一个函数实现两个字符串的比较,即自己写一个strcmp函数: strcmp(s1,s2)如果s1=s2,则函数返回值为0;如果s1≠s2,返回它们二者第一个不同字符的ASCII码差值(如“BOY”与“BAD”,第二个字母不同,“O”与“A”之差为79-65=14);如果s1>s2,则输出正值;如s1 两个字符串s1,s2由main函数输入,strcmp函数的返回值也在main函数输出。 实验十 结构体和共用体(4学时) 实验性质:设计性实验 一、实验目的 1.掌握结构体类型变量的定义和使用; 2.掌握结构体类型数组的概念和应用; 3.掌握共用体的概念与使用。 二、实验内容 编程序,然后上机调试运行。 1.有5个学生,每个学生的数据包括学号、姓名、三门课的成绩,从键盘输入5个学生数据,要求打印出三门课总平均成绩,以及最高分的学生的数据(包括学号、姓名、三门课的成绩、平均分数)。 要求用一个input函数输入5个学生数据;用一个average函数求总平均分;用max函数找出最高分学生数据;总平均分和最高分的学生的数据都在主函数中输出。 2.输入和运行以下程序: #include union data {int i[2]; float a; long b; char c[4]; }; void main(){union data u; scanf(“%d,%d”,&u.i[0],&u.i[1]); printf(“i[0]=%d,i[1]=%dna=%fnb=%ldnc[0]=%c,c[1]=%c,c[2]=%c,c[3]=%cn”,u.i[0],u.i[1],u.a,u.b,u.c[0],u.c[1],u.c[2],u.c[3]);} 输入两个整数10000、20000给u.i[0]和u.i[1]。分析运行结果。 然后将scanf语句改为: scanf(“%ld”,&u.b); 输入60000给b。分析运行结果。 实验十一 位运算(1学时) 实验性质:设计性实验 一、实验目的 1.掌握位运算的概念和方法,学会使用位运算符; 2.学会通过位运算实现对某些位的操作。 二、实验内容 编写程序,上机调试并运行。 1.设计一个函数,使给出一个数的原码,能得到该数的补码,用八进制形式输入和输出。 实验十二 文件(1学时) 实验性质:设计性实验 一、实验目的 1.掌握文件以及缓冲文件系统、文件指针的概念; 2.学会使用文件打开、关闭、读、写等文件操作函数。3.学会用缓冲文件系统对文件进行简单的操作。 二、实验内容 1.从键盘输入一个字符,将其中的小写字母全部转换成大写字母,然后输出到一个磁盘文件“test”中保存。输入的字符以“!”结束。实验十三 学生成绩管理(4学时) 实验性质:综合性设计性实验 一、实验目的 1.综合运用C程序设计知识,解决实际问题。 二、实验内容 1.有5个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号、姓名、三门课成绩),计算出平均成绩,将原有数据和计算出的平均分数存放在磁盘文件“stud”中。 2.将上题“stud”文件中的学生数据,按平均分进行排序处理,将已排序的学生数据存入一个新文件“stu-sort”中。 3.将上题已排序的学生成绩文件进行插入处理。插入一个学生的三门课成绩。程序先计算新插入学生的平均成绩,然后将它按成绩高低顺序插入,插入后建立一个新文件。 学生的原有数据为: 91101 Wang 89,98,67.5 91103 Li 60,80,90 91106 Fun 75.5,91.5,99 91110 Ling 100,50,62.5 91113 Yuan 58,68,71 要插入的学生数据为: 91108 Xin 90,95,60 制 订:程世辉 教研室:软件教研室 执笔人:程世辉 审定人: C语言提供了30多个运算符, 范围很大, 应用广。除了控制语句和输入、输出之外, 几乎所有的基本操作, 都是按照运算符来进行处理的, 可见其在C语言中的重要性。 1.C语言运算符的作用与分类 C语言的运算符可以灵活地与运算对象组合成运算表达式。按其在表达式中的作用, 运算符可分成基本运算符和其他运算符。基本运算符有8类, 即算术运算符、关系运算符、逻辑运算符、自增运算符、自减运算符、字位运算符、赋值运算符、条件运算符、逗号运算符等。而其他运算符有指针运算符和杂项运算符等。每类运算符又包含了多种运算符。 2.基本运算符 ⑴算术运算符及自增、自减运算符 表4列出了加、减、乘、除、取模5种算术运算符, 以及自增、自减运算符的操作说明。其中, 除法运算符又分两种情况, 一是整除, 即两个整数相除, 所得商舍尾数, 仅取整数部分, 如5/10等于0;二是实除, 即两个实数相除, 所得商也是实数, 如5.0/10等于0.5。 自增运算符++和自减运算符--, 是C语言中最具特色的单目 (一个量) 运算符, 其操作对象必须是整型变量, 而不能为常量或表达式, 其功能分别是使变量增1或减1。自增运算符++和自减运算符--有前缀运算符和后缀运算符两种应用方式, 两者产生的效果有些不同:前缀运算符, 如++i或--i, 在使用i之前, 先使i的值+1或-1;后缀运算符i++或i--, 在使用i之后, 才使i的值加1或减1。 例如, y的原值等5, 则: 语句X=++y, 表示y先加1再运算, 得y=y+1=6, x=y=6; 语句X=y++, 表示y先运算再加1, 得x=y=5, y=y+1=6。 在《电子制作》2009年第10期, 《PIC单片机C语言程序 (1) 》的延时函数中, 我们已用过后缀运算符i++, 大家可以从中体会其用法。 ⑵逻辑运算符 逻辑运算符是基本运算符中的一种。逻辑运算符有:与“&&”、或“‖”、非“!”等3三种。 逻辑运算符&&、‖为双目 (两个量) 运算符, !为单目运算符。它们要求的操作对象是非0的整型值和整型0表示的逻辑量。其运算规则如下: 1) 若两个操作对象都为非0整型值 (真) , 则相与的结果为1 (真) , 否则为0 (假) ; 2) 若两个操作对象都为整型值0 (假) , 则相或结果为0 (假) , 否则为1 (真) ; 3) 若操作对象为非0整型值 (真) , 求非的结果为0 (假) , 否则为1 (真) 。 这里补充一点, 算术运算符中的加、减和乘, 与大家熟悉的算术运算规则完全相同, 而除运算符应按上述规范使用。 C语言的运算符内容较多, 限于篇幅, 这里仅概况地加以介绍, 希望读者在学习时, 根据PIC单片机书籍, 深入学习C语言的运算符, 并通过编写C语言程序, 掌握每个运算符的意义和使用规则。 3.可预置起始时刻的时钟程序 ⑴硬件电路 利用《电子制作》2010年第1期《PIC单片机C语言程序 (4) 》一文中的4位LED数码管显示电路 (图3) , 可以制成24小时或12小时循环显示的时钟电路, 且该时钟可以由人工预置起始时刻, 即电路插上电源后, 可根据当时的实时时刻, 如手机或电视屏上显示的时刻, 进行人工校时, 之后即可作时钟用;若不进行人工预置 (校时) , 该电路就自动从00.00开始, 以分为单位起始计时, 此时, 该电路可作人工守侯定时器。该时钟电路不显示秒, 而是以分钟开始的显示。 该电路仍采用PIC16F84A芯片, 当写入本文下面给出的程序后, 即可作24小时时钟用。其使用方法如下: 插上电源, LED数码管显示00.00, 按下图3中的K1键, 数码管全灭, 松开K1键, 再按下K1键, 数码管从0 (分位) 开始计数, 到达指定的分钟显示时, 放开K1键, 又按K1键, 时位显示, 到达指定的时显示时, 放开K1, 时钟即按人工预置起始时刻工作, 操作十分简单。 注意:如果预置时间的时位是从00开始而仅有分钟的有效值时, 当预置分钟指定值后, 仍要再按下K1键, 使时位从00递增又回到00, 时钟即可工作, 否则时钟电路不会工作。 ⑵24小时的时钟C程序 根据图3编写的24小时时钟电路的功能, 可绘出相关流程图 (限于篇幅, 这里从略, 若需要, 可根据《PIC单片机C语言程序 (4) 》一文的图5, 0~9999的计数流程图, 加上下面的C程序中的注释, 扩展绘出) , 再由流程图编写出24小时的时钟C程序。该程序命名为pic0.5.c, 其清单如下: 说明:1) 上述C程序, 经picc编译器编译, 生成目标码.hex, 即可用编程器将.hex程序烧写到pic16F84A芯片中, 再用《PIC单片机C语言程序 (4) 》一文中图3电路即可制成24小时的时钟。该时钟与标准时间相比, 仅慢1秒/周。略增、减本程序中的d值, 可再校时。 2) 初学者仔细查看程序中的注释, 即可理解本C程序的编写原理。 关键词:工作过程;C语言程序设计;单片机课程;电子设计竞赛 一、C语言程序设计在电子类专业中的现状 第一,单片机和C语言课程独立开设的,C语言的教学一般由计算机部门的教师担任,教学围绕的目标是学生的等级考试,教学内容全校一样,不能根据各专业学生的需求“量身定做”。而单片机课程由本学院的教师担任。教授C语言和教授微型单片机课程的教师之间交流、沟通少,课程之间的衔接少;第二,《C语言程序设计》课程通常以普通PC机作为C语言运行的主要硬件平台,学生不理解C语言有什么用,缺乏学习的动力,而且教学方法单调,模式单一,学生只是被动接受,缺乏主动参与;第三,单片机课程陆续引入了C语言进行教学,将教学内容项目化,采取项目引导、任务驱动的教学模式,取得了一定效果。但改革的力度仅仅局限在单片机课程内部,而忽视了前序课程《C语言程序设计》的统筹改革,因此其改革的力度和效果非常有限[2];第四,在教学思想方面,忽视了对学生实践能力和技能的培养,失去了高职院校的特色。因此,迫切的需要该课程无论在教学内容上,还是教学方式上都要改进和革新。 二、课程改革思路 高职教育理论研究和实践结果表明,加强教学过程的实践性、开放性、职业性,有利于提高学生职业技能水平。本研究以教育部文件精神为指导,根据应用电子技术专业的培养方向,必须加强与微型单片机有关的课程间的衔接,增加新知识与新技术,删除过时的内容,优化课程体系,与企业合作,建立突出实践能力培养的《单片机与C语言程序设计》课程标准,改革教学内容和教学模式,克服传统的《C语言程序设计》课程和单片机课程衔接不够紧密、科学的弊端,提高教学质量。 三、课程改革方法和措施 (1)提高学生学习兴趣。工程教学中始终贯穿着项目,学生按工程项目的任务、要求有针对性地学习知识,学习目的明确,学习热情高涨,由过去传统教学过程中的“厌学”,到现在的“爱学”,充分体现工程教育模式对学生的学习热情的激发作用;(2)提高教学效率。建立一套包括理论讲授、计算机辅助教学、实践教学在内的全方位的课程教学新体系,积极主动地运用现代化教育手段,更新教学手段,使用电子课件、多媒体教学设施等,充分调动教师和学生两方面的积极性,提高课程的教学质量和课堂教学效率。(3)增强学生实践应用能力。在工程教育的教学模式下强调教学与实践一体化,贯彻“学中做、做中学”的理念。教学过程中安排了大量的实践活动,学生亲自动手完成项目要求的各个实践任务,有些实验必须不断修改程序、反复调试才能达到项目设计要求,从而提高学生的思维和实践动手能力。(4)提高任课教师的师德、业务素质与水平,建立一支高水平的教学和研究梯队。 四、课程总体设计 本研究提出了一种基于工作过程的C语言课程与单片机课程有效结合的课程改革模式,如下图1所示。 图1 改革后的课程体系 从工作过程出发,将课程整体综合项目的应用分解为C语言课程任务、C语言与单片机的结合、单片机课程任务三个部分,C语言课程任务和单片机课程任务两者服务于C语言与单片机的结合;C语言课程任务主要面向C语言程序设计的知识点学习即C语言的课程领域;C语言与单片机的结合又可分解为C语言在单片机中的算法学习和单片机中的C语言程序设计;单片机课程任务主要面向单片机内部资源的学习即单片机课程领域;最后将两者优化整合,形成《单片机与C语言程序设计计》课程。 总结:本文融“教、学、做”为一体的教学模式,强化学生单片机系统应用能力的培养,将单片机课程与C语言课程进行了有机整合。课程整合以来,学生兴趣浓厚、学习效果大为提高,并为历届的全国大学生电子设计竞赛大赛参赛学员的储备和选拔提供了良好支撑。作为学院唯一与全国大学生电子设计竞赛大赛相关的院系,应用电子技术专业今年第七次代表学校参加比赛,我校竞赛小组每年均获得湖北省一等奖, 特别在2011年的大赛中一举取得了高职高专组全国一等奖的佳绩[2]。教学实践证明,课程改革效果良好,极大地提高了学生对实际问题进行电子设计制作的能力,促进了学生学生工程实践能力的培养。 参考文献: [1] 阮越广.基于工作过程的高职单片机 C 语言教学设计[J].大学教育,2012.3:57-58 东西方向60秒,南北方向57秒 #include #define ON 0 #define OFF 1 sbit NS_G=P2^5;//南北绿灯 sbit NS_Y=P2^4;//南北黄灯 sbit NS_R=P2^3;//南北红灯 sbit EW_G=P2^2;//东西绿灯 sbit EW_Y=P2^1;//东西黄灯 sbit EW_R=P2^0;//东西红灯 sbit LED_D1=P3^7;//南北方向数码管位控制 sbit LED_C1=P3^6;//南北方向数码管位控制 sbit LED_B1=P3^1;//东西方向数码管为控制 sbit LED_A1=P3^0;//东方向数码管位控制 /*********倒计时赋初值*************/ uchar EWF=20,NSF=17,X=20,Y=17,Z=20,SHU=20;uchar count; void Init(void){ TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;ET0=1;TR0=1;} /*******************中断服务程序**************************/ void timer1(void)interrupt 1 { TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;ET0=1;TR0=1; count++;if(count>19){ EWF--; NSF--; X--; Y--; Z--; SHU--; count=0; } } /******************延时**********************/ void Delay10uS(uchar z){ uchar x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);} /******************led控制*******************/ unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极数码管赋值 void display1(uchar num1,uchar num2) //控制东西方向led显示 { P0=table[num1]; LED_A1=ON; Delay10uS(1); LED_A1=OFF; P0=table[num2]; LED_B1=ON; Delay10uS(1); LED_B1=OFF; } void display2(uchar num3,uchar num4)//控制南北方向led显示 { P0=table[num3]; LED_C1=ON; Delay10uS(1); LED_C1=OFF; P0=table[num4]; LED_D1=ON; Delay10uS(1); LED_D1=OFF; } void main(){ int i;/************初始状态东西南北禁止通行************/ NS_R=ON;//南北方向红灯打开 EW_R=ON; //东西方向红灯打开 for(i=0;i<600;i++) { Delay10uS(20); } NS_R=OFF;//南北方向红灯关闭 EW_R=OFF;//东西方向红灯关闭 while(1) { Init(); // 初始化计时器 /****************状态1:东西绿灯(57s),南北红灯(60s)**************/ /***************状态2:东西黄灯(3s),南北红灯(60s)****************/ EW_G=ON;//东西方向的绿灯打开 NS_R=ON;//南北方向的红灯打开 while(EWF!=0) { display1(EWF/10,EWF%10);// 东西方向红灯(60s) display2(NSF/10,NSF%10);// 南北方向绿灯(57s) while(EWF==3) { while(X!=0) { display1(EWF/10,EWF%10);// 东西方向红灯(3s) display2(X/10,X%10);// 南北方向黄灯(3s) EW_G=OFF;// 东西方向的绿灯关闭 EW_Y=ON;// 东西方向的黄灯打开 } } } NS_R=OFF;// 南北方向的红灯关闭 EW_G=OFF;// 东西方向的绿灯关闭 EW_Y=OFF;// 东西方向的黄灯打? /*=*************状态3:东西红灯(60s),南北绿灯(57s)************/ /****************状态4:东西红灯(60s),南北黄灯(3s)***************/ EW_R=ON;// 东西方向的红灯打开 NS_G=ON;// 南北方向的绿灯打开 while(Z!=0) { display2(Z/10,Z%10);// 南北方向红灯(57s) display1(Y/10,Y%10);// 东西方向绿灯(57s) while(Z==3) { while(SHU!=0) { display2(Z/10,Z%10);// 东西红灯(3s) display1(SHU/10,SHU%10);// 南北绿灯(3s) NS_G=OFF;//南北方向的绿灯关闭 NS_Y=ON;// 南北方向的黄灯打开 } } } } EW_R=OFF;// 东西方向的红灯关闭 NS_G=OFF;// 南北方向的绿灯关闭 NS_Y=OFF;// 南北方向的黄灯关闭 EWF=60,NSF=57,X=60,Y=57,Z=60,SHU=60;//重新赋值 8.1 在定义的时候,*ap中的‘*’是指针类型说明符; 在进行指针预算时,x = *ap 中的‘*’是指针运算符。8.2 如果在已定义好的指针变量,并引用,即 int *ap, int a;ap = &a;则在进行指针运算的时候: (1)*ap与a是等价的,即 *ap就是a; (2)&*ap:由于*ap与a等价,则&*ap与&a等价(地址); (3)*&a:由于&a = ap,则*&a与*ap等价,即*&a与a等价(变量);(4)*ap++相当于a++。 8.3 指向数组的指针变量的定义,应用,赋值: int a[10];int *app;则有两种方法:app = &a[0];或 app = &a;(1)app+I 或a+i就是数组元素a[i]的地址;(2)*(app+i)或 *(a+i)就是元素a[i]中的内容; (3)指针变量也可以带下表,即app[i]与*(app+i)等价。8.4 数组和指针可以互换,但在代码执行的效率上却大不相同。用数组找元素必须每次计算元素的地址,效率不高;而用指针则直接指向某个元素,不必每次计算地址,可以大大的提高运算效率。8.5 关于指针的运算: (1)p++(或p+=1):使指针p指向下一个数组元素,地址加1; (2)*p++:先得到p指向的变量值,再执行p加1,指向下一个数组元素;(3)*++p:先使p加1,指向下一个数组元素,再去p指向的变量值;(4)(*p)++:表示p指向的变量值加1; (5)若p指向当前数组中的第i个元素,则: (p--)与a[i--] 等价:先执行*p,然后p自减;(++p)与a[++i] 等价:先执行p自加,再执行*p;(--p)与a[--p] 等价:先执行p自减,再执行*p。 8.6 指向多维数组: 定义一个二维数组:a[3][4];定义一个指针变量:(*p)[4];(注意:列数相同(第二维相同))使指针变量指向数组:p = a;此时: p与a等价:指向数组a[3][4]的第0行首地址; p+1与a+1等价:指向数组a[3][4]的第1行首地址; p+2与a+2等价:指向数组a[3][4]的第2行首地址; 而: *(p+1)+3与& a[1][3]等价,指向a[1][3]的地址; *(*(p+1)+3)与a[1][3]等价,表示a[1][3]的值; 一般的:对于数组a[i][j]来讲,有 *(p+i)+j相当于&a[i][j],表示第i行第j列元素的地址; *(*(p+i)+j)相当于a[i][j],表示第i行第j列元素的值。 8.7 指向结构体: 如果指针p指向结构体数组msg1[0]的首地址,则: (1)(*p).flg与p->flg和msg1[0].flg三者完全等价,即(*p).成员名 与p->成员名 以及 结构体数组元素成员名三种形式是等价的; (2)p+1:使指针指向结构数组msg1[0]的下一个元素msg1[1]的首地址;(3)由于指向运算符->的优先级高于自加运算符++,则: (++p)->flg:先使p自加1指向msg1[1]的地址,再指向msg1[1]的flg成员值;(p++)->flg:先得到msg1[0].flg的值,再使p自加1指向msg1[1]的首地址; 二、片上资源丰富。MEGA系列片上具备JTAG仿真和下载功能。片内含有看门狗电路、片内程序Flash、片内数据RAM、同步串行接口SPI、异步串口UART、内嵌AD转换器、EEPROM、模拟比较器、PWM定时计数器、TWI(IIC)总线接口、硬件乘法器、独立振荡器的实时计数器RTC、片内标定的RC振荡器等片内外设,可以满足各种开发需求。 三、驱动能力强。I/O口可以直接驱动数码管、LED、继电器等器件,节省很多外围电路,即节省开发难度,又降低成本。 四、功耗低。低功耗虽然比不上430单片机,但是在单片机中也是佼佼者。 五、可选择型号种类多。各种不同的型号可以满足不同的需求,让你的项目有很多的选择余地。 当前对于单片机来说, 其应用越来越广泛, 生产半导体的厂家对于各类低、中、高档的单片机系列不断推陈出新, 从而适应市场的大力需求。早期的单片机程序, 一般都是以汇编语言来进行编写, 因为利用汇编语言编写的程序, 更为简捷和直接, 并且对于如存储器和I/O设备口等硬件设备, 能够进行非常有效的控制和访问。不过由于是面向机器的语言, 汇编语言在不同厂家以及相同厂家不同系列的单片机类型上, 一般会出现不兼容的现象, 于是就出现了对于PIC及其他单片机, 不能使用汇编语言进行语言源程序编写的现象。另外, 因为不同单片机程序难以移植、产品升级换代等原因, 以及采用助记符的低级语言的汇编语言, 具有非常差的可读性, 及时阅读自己编写的程序也容易产生困难感, 这些因素对于汇编语言在PIC单片机上的应用, 正是其发展瓶颈所在。 随着C语言的开发利用, 在PIC单片机上利用C语言来进行相应的程序设计, 并且具有直观的软件调试、高效率的代码、方便维护和升级、代码重复利用率高以及非常方便的跨平台代码移植等诸多优点, C语言在单片机的程序设计中, 得到了大量而广泛的应用。 1 C语言概况介绍分析 1.1 简洁的语言 由于是一类小型语言, 因而C语言只有32个关键字和9个控制语句, 表示方法也相对简单, 仅仅需要用比较规范的方式方法, 就能够对于很强的数据类型、程序结构和语句进行相应的构造。 1.2 实用并且灵活的表达方式 提供多个表达式和运算符的方法, 是C语言又一大特征。这个特征就表明了, 可以通过多类途径对于问题进行表达, 并且更加灵活而主动的对于程序进行设计。因为没有严格的对于语法进行限制, 因而有着比较大的自由空间提供给程序设计。 1.3 非常强大的表达能力 具备非常丰富的运算符和数据结构的C语言, 对于各种数据结构都进行了包含, 从而对于各类数据结构能够实现和进行相应的运算。C语言一共有34种运算符, 灵活和范围广泛都使得它能对于难度极大的运算, 非常理想的得以实现。对于硬件的物理地址来说, C语言能进行直接的方位和位操作, 因此具备了低级语言和高低语言兼有的更多优势特征。另外, C语言既能对于系统软件进行编写, 又能对于应用软件进行开发, 因而现在已经成为业内一个比较普遍且通用的程序设计语言。 1.4 程序设计结构化 因为结构化语言是C语言的最大特征所在, 因此对于程序结构化所需要的控制流的结构语句, 能够提供相应的条件进行编写。作为程序设计的基本单位, 可以利用函数来对于程序的模块化实现程序, 并且还可以分割成多个源文件, 从而编译出各个源文件, 最后生成可执行的目标码文件。 1.5 高质量的语言生成目标代码 由于具有小工作量、比较好的可读性、非常方便且容易的修改、调试和移植, C语言比起汇编语言来描述问题更为迅速, 并且和汇编语言相比代码质量更是旗鼓相当。 1.6 具有可移植性 C语言和汇编语言是不同的, 体现在后者无法进行移植, 而C语言在不同机器上进行C编译程序, 公共代码占到85%以上, 因而方便移植是C语言编译程序的又一优势特征。一般不需要改动或者稍微加以改动, 就能够对于C语言在某个环境下编写的程序进行移植, 并且运行在另外一个完全不同的环境中去。 2 简单的C语言程序概述 对于程序所要用到的C语言基本知识, 本文对此做些简单介绍: 2.1 主函数main () 一般情况下, C语言由若干个函数构成。这里所说的函数, 是指某个功能的算法程序段, 同时也是构成C语言的基本单位。一个程序的若干组成函数, 可以在一个甚至几个源程序文件里进行保存, 并且以.C为基本扩展名, 而一般的汇编语言的扩展名都是ASM。在一个程序中, 一般有且只有一个main为名称的函数, 也就是主函数。一般运行程序的时候, 开始执行的都是主函数main () 。 2.2 C语言函数概述 函数是C语言程序的基本单位。在一个C语言程序中, 有且只有一个主函数并且名为main () 。这个主函数, 可以对于其他函数进行调用, 其他的函数也可以在互相之间进行调用。在被调用的函数中, 既可以是程序设计者自行编写的函数, 也可以是系统提供的库函数。函数头和函数体, 共同组成了一个函数的两个部分, 并且具有相同的函数形式。 2.2.1 由自定义名或者称之为函数名、一对圆括号的函数标志、函数 形式参数名 (又称参数表) 、定义形式参数类型 (参数说明) 这几个部分共同组成。其中, 函数名和函数标志为必须, 其他选项则是根据需要进行确定。需要强调的是, 包括了函数名字和函数类型, 才能共同组成函数名。 2.2.2 由一对花括号{}括起来的部分, 就是函数体部分。 这个括号内的内容组成, 一般是由若干语句。在这些语句中, 一类是执行语句, 也就是函数功能的执行部分功能的内容;一类是说明语句, 也有称作变量定义, 它能起到对于函数中用到的变量进行定义的作用。 算法处理是对于一定的功能进行并完成的过程。这里有一类情况需要说明, 没有变量定义部分, 但是可能存在若干的执行语句, 有的函数就存在这样的情况。如果在特定的情况和环境之下, 则既没有执行部分, 也没有声明部分。比如一个空函数, 即使什么也没有表示和执行, 也依然是一个合法的函数。 另外, 在数据定义和每个语句的最后, 都要有一个分号来加以表示。在C语言环境中, 最先接触到的基本符号, 就是分号。 2.2.3 赋值运算符中的赋值号“=” 在赋值运算符中, 有三个表达的方式, 本文分析的是最简单的赋值运算符: 对于表达式值进行计算, 对于这个值赋给出等式左边的变量来。一般按照从左到右的顺序, 对于赋值运算符进行计算和作业, 可以通过变量=表达式的格式, 对其进行表示。 3 C语言程序编写 对于某单片机端口寄存器外接的几个LED灯的亮和灭, 本文通过编写C程序语言, 来对于这些灯光进行相应的控制。 本文使用集成开发环境和PICC的编译器, 生成了C语言源程序, 也就是相应的源文件。 对于硬件的标志头文件, 也就是头文件或者包含头文件进行定义, 这是编写C源程序时所首先必须做的。一般而言, 用户经常要用到的标准寄存器和其位地址, 都在Pich的标志头文件里能够被相对应的进行定义, 并且通过C语言相关的编译器, 按照编译源程序的语法规则进行详细的定义, 并且使用#include语句来把这个头文件, 包含到相应的源程序之中。这样下来, 对于PIC里中级产品的单片机, 就能把相应的内容复制到对应的源程序里, 并且对于标准寄存器的位地址和端口地址进行定义, 源程序就能合法对于这些标准寄存器和对应位进行使用。 4 结束语 对于C语言来说, 在PIC单片机上进行的程序设计, 是为了实现相应的程序目标。具体的C语言程序设计的范畴和案例, 本文由于篇幅有限, 不能进行详细叙述, 需要各位从事本行业的相关人员积极探索, 开拓创新出更多优秀案例来。 参考文献 [1]廖文江, 等.以开源软件为平台改进C语言教学[J].计算机时代, 2009, (10) :61-62.[1]廖文江, 等.以开源软件为平台改进C语言教学[J].计算机时代, 2009, (10) :61-62. [2]何钦铭, 颜晖“.C程序设计基础及实验”国家精品课程的建设经验[J].计算机教育, 2008 (19) :28-31.[2]何钦铭, 颜晖“.C程序设计基础及实验”国家精品课程的建设经验[J].计算机教育, 2008 (19) :28-31. 单片机原理及其应用是我国高职院校电子类及相关专业的必修课程。随着国家电子信息产业的发展,单片机在电子技术中的应用越来越广泛,电子电路设计基本上都是以单片机为核心的综合性的应用。因此,提高单片机的教学效果,对提升学生的实践创新和解决问题能力的培养有着重要的现实意义。 一、单片机技术的特点 单片机课程是一门集合计算机技术、电子技术、自动化控制技术等在内的综合性、实践性很强的课程,其特点如下:单片机的概念繁多、专有名词多、内容比较抽象,学生普遍认为入门很难;单片机汇编语言编程指令多达111条,且要掌握每条指令的功能、操作数源和书写规范的语法;单片机开发的系统性、逻辑性、完整性很强,软硬件知识衔接紧密。 基于单片机的这些特点,笔者在教学中,对教学内容、教学方法和培养学生创新能力方面进行了改革与探索,对提高整体教学水平和教学质量起到了良好的推动作用。 二、教学内容的改革 根据该课程的特点,笔者在教学过程中注重对教学内容的优化组合,揭示出单片机的神奇所在。通过一个简单有趣的实验,激发学生的学习兴趣,使之在单片机学习上找到自信。 传统单片机学的都是汇编语言。为了使学生更好地入门并增强程序的可读性,我们采用单片机C语言编程的教学模式。C语言与汇编语言相比有良好的可读性,灵活性也更强,而且不需要记忆那么多指令的使用规则,主要掌握C语言中的for、while、if 、switch-case等语句,另外再了解C语言中数组的概念即可。 单片机系统是一个软硬件结合的综合系统,单一进行程序的仿真不足以让学生全面了解单片机应用的系统性、逻辑性和完整性。因此我们在教学过程中,注重利用proteus软件让学生进行系统的软硬件设计,进行仿真练习,使学生产生对单片机学习的兴趣,同时降低学习的难度提高学习效率,加快由知识到能力的转化。 三、教学方法的改革 以往的实验实践教学,都是让学生按照实验设备提供商的实验指导书或者是教材内提供的实验进行连线和下载程序,这样不利于提高学生的动手能力和创新能力,而且禁锢了学生的创造力。为了取得更好的教学效果,我们结合日常生活中一些单片机使用实例,采用任务驱动的教、学、做一体化教学模式。例如讲到定时器/计时器的使用时,首先给学生详细讲解单片机定时器/计时器设置方法,然后给学生演示如何利用定时器/计时器设计一个秒表的软硬件电路,再给学生布置一个利用定时器/计时器设计一个数字钟的单片机系统的课堂作业。学生可以分成三人一个团队,共同讨论设计方案,然后三人分别负责程序软件设计、电路硬件设计和实验报告撰写,最后共同进行电路制作调试。在设计过程中,教师主要解决学生遇到的不同问题,完成一个系统设计后,再带着学生一起对教学内容进行总结反思,达到举一反三、触类旁通的教学效果,同时也能使学生完全参与到课堂中,在交流中激发创造性。这一教学过程主要践行教、学、做一体化的教学模式,使学生能够在做中学、学中做,激发学习兴趣,增强自信心和成就感,培养团队协作意识,为以后参加工作打下一个良好的基础。最后,教师根据每位学生在团队中的表现和做出的电路的效果进行综合打分并计入平时成绩。 四、教学评价模式的改革 我们改变了以往试卷式的期末考核方式,采用项目负责制进行考核。在期末考试前一个星期内,任课教师给每个学生团队布置一个综合性的任务课题,要求学生按照课题要求进行软硬件电路的设计、组装、调试、成型。教师最终根据电路功能效果和学生在此过程中的参与度及电路成本、设计制作周期等综合因素进行打分作为期末考试成绩。这种期末考核方法主要考查学生对电路设计制作以及电子电路基础知识的综合应用,避免了学生只会动笔而不会动手的现象,培养了学生独立思考、分析、解决实际问题的能力和创新意识。对电路成本和设计周期的考核,主要为了使学校培养与企业用工有机结合,使学生能够更好、更快地融入到工作岗位,为以后从事单片机研发工作打下一个基础。 小学期AVR单片机实验报告 实验题目: 基于ATmega16L单片机的电子琴设计 学生姓名:学渣 班 级:2012XXXXXX 班内序号:XX 学 号:2012XXXXXX 日 期:2014年9月30日 同组同学:学渣 第1页 北京邮电大学信息与通信工程学院 目录: 一、实验介绍......................................3 1.1实验课题名称.................................3 1.2实验平台.....................................3 1.3实验课题关键字 ..............................3 1.4实验摘要.....................................3 二、小组分工......................................3 三、基本题目训练——流水灯与数码管秒表计时器.......3 3.1实现功能......................................3 3.2程序代码分析..................................4 3.3实验结果图片...................................7 四、有关发声的基础知识............................7 五、电子琴的设计与测试..............................9 5.1设计过程......................................9 5.2实验所需元器件.................................9 5.3实验程序主要流程图.............................10 5.4实验原理及原理图...............................10 5.4.1实验原理....................................10 5.4.2原理图.....................................11 5.5各个模块的设计与讲解............................11 5.6程序源代码及程序分析..........................14 5.7实验结果.......................................24 六、排错过程.........................................26 七、心得体会..........................................29 八、参考文献..........................................32 九、意见与建议........................................33 第2页 北京邮电大学信息与通信工程学院 一、实验介绍: 1.1实验课题名称:基于ATmega16L单片机的电子琴设计 1.2实验平台:本实验所用平台为AVR Studio 4 1.3实验课题关键字: ATmega16L型单片机 电子琴 键盘按键 LCD液晶显示屏 1.4实验摘要: 本实验设计的电子琴拥有可视化操作界面,能实现即时弹奏音乐、音乐播放、音乐变速、音乐变调,并可以进行任意长度录音(通过按键记录音阶)等功能 二、小组分工: XXX负责电路硬件的连接和报告的撰写 XXX负责程序代码的编写 XXX负责资料的收集整理和查阅 三、基本题目训练——流水灯与数码管秒表计时器 3.1功能:八盏LED二极管按顺序依次循环点亮,实现流水灯的效果,同时两只数码管分别代表秒和十分之一秒,进行秒表计时,配有 第3页 北京邮电大学信息与通信工程学院 两个按键,实现计时过程中的暂停和继续,同时在按下暂停键的时候蜂鸣器会响一声。利用ATmega16的寄存器中断功能,实现流水灯和数码管秒表计时器在实验板上同时工作,并且互相独立不影响。 3.2程序代码分析: #include #include char b[10] = { 0b11111010,//0 0b00110000,//1 0b11011001,//2 0b01111001,//3 0b00110011,//4 0b01101011,//5 0b11101011,//6 0b00111000,//7 0b11111011,//8 0b01111011,//9 };char a[10] = { 0b11111010,//0 0b00110000,//1 0b11011001,//2 0b01111001,//3 0b00110011,//4 0b01101011,//5 0b11101011,//6 0b00111000,//7 0b11111011,//8 0b01111011,//9 }; volatile char temp; int main(void){ DDRA = 0xff;PORTA = 0b10000000;DDRC = 0xff; 第4页 北京邮电大学信息与通信工程学院 DDRD = 0b11111011;DDRB = 0b11111011; TCNT0 = 55;PORTB = b[0];PORTD = a[0];PORTC |=(1 << 0);TCCR0 |=(1 << CS01);int count1 = 0,count2 = 0,i; MCUCR |=(1 << ISC00)|(1 << ISC01);//INT0上升沿触发 GICR |=(1 << INT0);//使能INT0,INT1 sei();//使能全局中断 while(1){ for(i = 0;i<9000;i++) { while(!(TIFR &(1< TCNT0=55; } count1++; if(count1!=10) PORTD = a[count1]; else { count2++; count1 = 0; if(count2 == 10) count2 = 0; temp = PORTA; PORTA = PORTA >> 1; if(temp & 0b00000001) { PORTA = PORTA | 0b10000000; } PORTB = b[count2]; PORTD = a[0]; } } } SIGNAL(SIG_INTERRUPT0)//INT0中断服务程序 { int count3 = 0,count4=0; 第5页 北京邮电大学信息与通信工程学院 while(!(PINB &(1<<2))) { count3++; if(count3 == 10) { count4++; count3 = 0; temp = PORTA; PORTA = PORTA >> 1; if(temp & 0b00000001) { PORTA = PORTA | 0b10000000; } } for(int i=0;i<9000;i++) { while(!(TIFR &(1< TCNT0=55; } } } 第6页 北京邮电大学信息与通信工程学院 3.3实验结果: 四、有关发声的基础知识: 声波是振动产生的。频率即表示每秒钟振动的次数,采用CTC方式时AVR单片机通过特定的端口(PD4及PD5)输出一定频率的方波,TCCR1A设为比较匹配时OC1A/OC1B电平取反,TCCR1B的计数上限为 第7页 北京邮电大学信息与通信工程学院 OC1A,根据公式OCnA=f/2N(1+OCRnA)计算出7个频率音阶所需的OCR1A,则只需将喇叭接在PD4或PD5,通过程序控制端口输出特定频率的方波波形(发声使用正弦波最好,方波效果稍次但影响不大),喇叭就会发出七种不同的声音,依照人听觉分辨7个音阶分为三组,分别为高中,低音阶频率,经计算可得,当OCR1A=(500000/musicmem[i]-1)时,{131,147,165,175,196,220,247}存放低音阶频率,{262,294,330,349,392,440,494}存放中音阶频率,{524,588,660,698,784,880,988}则存放高音阶频率,所以需要定义三个数组存放各音阶的频率值。除了音符频率以外还需要音长,所以定义1个2位数组表示一段音乐,第一个表示频率,第二个表示音长,播放时先访问频率数组,使喇叭发声,之后访问音长数组,确定喇叭发声时间。而有了音符频率数组,只要再得到任意一首歌的简谱,就可以将其转化为两个数组的形式,由音符对应的频率得出频率数组,然后再根据每个音符的音长,将其通过乐曲的节拍和音符的拍数计算出音符持续时间即可得出音长数字。 第8页 北京邮电大学信息与通信工程学院 五、电子琴的设计过程: 5.1设计过程: 5.2 实验所需元器件: ATmega16L型单片机,JTAG下载器,扬声器,4*4矩阵键盘,液晶屏,LM386,实验盒(内装剪刀、镊子、导线等用品)等 第9页 1602LCD北京邮电大学信息与通信工程学院 5.3实验程序主要流程图: 5.4实验原理及原理图 : 5.4.1实验原理 : 以ATmega16单片机作为整个系统的控制中心,外加琴键控制模块、播放模块、显示模块,使制作的电子琴完成设想的功能。琴键控制模块为4*4矩阵键盘,可以通过按下不同的琴键弹奏出不同的音阶,每个音阶对应着不同的频率,一段音乐是由许多不同的音阶组成,这样我们就可以根据不同的频率组合得到我们想要的音乐,同时在录制模式下,还可以通过按不同的按键记录下不同的音阶,由此记录一段音乐。播放模块接收对应频率的方波,由此播放琴键弹奏的音阶以 第10页 北京邮电大学信息与通信工程学院 及播放预先存放在单片机里的音乐。显示模块显示出当前所处的模式。 5.4.2 原理图: 5.5各模块的设计与详解: 中央处理器——ATmega16: 第11页 北京邮电大学信息与通信工程学院 实验中,PB0~PB7全部设置为输出,分配给LCD液晶显示屏D0~D7管脚;PA0~PA7连接4*4矩阵键盘的八个引脚;PD4、PD6和PD7设置为输出状态,分别连接到LCD显示屏的RS、R/W和E端口上;PD5置为输出状态,接到扬声器的一个管脚,扬声器的另一管脚接地;VCC为电源,向LCD显示屏供电;GND为公共接地。 琴键控制模块——4*4矩阵键盘: 工作原理:按键设置在行、列线交点上,行、列线分别连接到按键开关的两端。行线通过上拉电阻接到+5V 电源上。无按键按下时,行线处于高电平的状态,而当有按键按下时,行线电平由与此行线相连的列线的电平决定。 显示模块——LCD液晶显示屏: 第12页 北京邮电大学信息与通信工程学院 引脚详解: 第1脚:VSS为地电源。第2脚:VDD接5V正电源。 第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。 第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。 第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第13页 北京邮电大学信息与通信工程学院 第15脚:背光源正极。第16脚:背光源负极。 播放模块——扬声器: 原先以为单片机本身的电源电压不足以驱动扬声器工作,所以设计了有LM386的功放模块,后来在实际操作的过程中测试发现,单片机本身的电源足以驱动扬声器播放音乐音调,因此舍弃了LM386功放模块的设置。 5.6程序源代码及程序分析: #include #include #pragma data:code #define uchar unsigned char #define uint unsigned int const uchar table[]=“HELLO WELCOME!”; volatile uint num=0,count=0;volatile uint Mode=0,list=2,pause=0,aim=0,sure=0,del=0;volatile int state=0, S=1; //定义全局变量,S为变速变量 const uint Mode_Data[16]={0,440,494,523,587,659,698,784,880,998,1046,1156,1318,1396,1568};//存放声音的频率 //音高对应定时器初始化数值(低la~高la+休止符),cpu频率1MHz,用8分频 const uchar tone[]={0x00,0x8E,0x7E,0x77,0x6A,0x5E,0x59,0x4F,0x47,0x3F,0x3B,0x35,0x2F,0x2C,0x27,0x23,0X19,0X15}; uint Ssong[10][2]={{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; //******************************************** void delay_us(int n) //微妙级延时函数; { 第14页 北京邮电大学信息与通信工程学院 while(n--){ asm(“nop”);//自动延时一个时钟周期什么也不做 } } void delay_ms(int n) //毫秒级延时函数; { int m=14500*n;while(m--){ asm(“nop”);} } //********************************************** /************************ 屏幕显示函数 ************************/ void write_com(uchar com){ PORTD&=~(1<<4); //低电平指令模式。高电平数据; PORTD&=~(1<<6); //低电平写; PORTB=com;PORTD|=(1<<7); //高电平使能 delay_ms(1);PORTD&=~(1<<7); } void write_dat(uchar dat){ PORTD|=(1<<4);PORTD&=~(1<<6);PORTB=dat;PORTD|=(1<<7);delay_ms(1);PORTD&=~(1<<7);} /*********************************** * 音乐产生函数 * * 功能:输出频率为x的方波* * 范围:x:100-20000Hz,0:不发声 * * ***********************************/ 第15页 北京邮电大学信息与通信工程学院 void sound(int i) { TIMSK|=(1<<2);sei(); if(i&&i<17) //按了音符键了,且在0到F键这16个发音键上,才发声 { OCR1A=tone[i]; TCCR1A=0X50; //控制寄存器,选择可翻转功能,产生方波; TCCR1B=0X0a; PORTD=(1<<5);} else { TCCR1A = 0x00; //频率为0,休止符,不发声 TCCR1B=0X00; OCR1A=0; } } /************************************ 弹奏函数 ************************************/ void play(int n) //参数为键盘上的数字; { write_com(0X80+0X40+n);write_dat(16);sound(n); //弹奏音符; delay_ms(1);write_dat(20); TCCR1A=0x00; TCCR1B=0X00; //中断,为下一个节拍做准备; PORTD|=(1<<5); //PD5作为输出管脚,接扬声器; } //___________________________________________ void INI_POTR(void){ DDRD|=0xff;DDRB=0xff; PORTD=(1<<5);PORTD&=~(1<<7);DDRA=0xff; //A口作为键盘输入口; DDRB=0xff; } //_____________________________________ 第16页 北京邮电大学信息与通信工程学院 void INN_DEVICE(void){ MCUCR=0X00; // 中断寄存器置零; } //____________________________________ //检测键盘是否被按下的函数 uint isKeyPress(){ DDRA=0xff; //初始设置端口均为输出 PORTA=0xf0; //设置端口的初值为11110000 DDRA=0xf0; //将低四位设为输入 if(PINA == 0xf0) //当没有按下时,PINA仍然为11110000 { DDRA=0xff; return 0; //返回0,代表未按下 } else //当按下后,PINA不再是11110000 { DDRA=0xff; return 1; //返回1,代表按下了 } } //键盘输入检测函数; //_______________________________ int key_in(void) { DDRA = 0xff; //先全部设置为输出,再将后四位置为输入 PORTA = 0xf0; //设置高低电平 DDRA = 0xf0;uint i = 0,j = 16,Key = 17; unsigned char temp1,temp2; if(isKeyPress()){ temp1 = PINA; temp1 &= 0x0f; //只关心低四位的情况 switch(temp1) { case 0b00000001: j = 0; break; case 0b00000010: j = 1; 第17页 北京邮电大学信息与通信工程学院 break; case 0b00000100: j = 2; break; case 0b00001000: j = 3; break; } temp2 = PINA; temp2 &= 0x0f; if(temp1!= temp2) return 17; DDRA = 0xff; PORTA= 0x0f; DDRA = 0x0f; temp1 = PINA; temp1 &= 0xf0; switch(temp1) { case 0b00010000: i = 0; break; case 0b00100000: i = 1; break; case 0b01000000: i = 2; break; case 0b10000000: i = 3; break; } temp2 = PINA; temp2 &= 0xf0; if(temp1!= temp2) return 17; Key = i*4 + j+1;// return Key; } } /***************************** //去抖动 //只关心高四位的情况第18页 北京邮电大学信息与通信工程学院 音乐播放函数; *****************************/ void m_sound(uint a){ int m=(62500/a)-1; //发声原理 OCR1A=m; TCCR1A=0X50; //控制寄存器,选择可翻转功能,产生方波; TCCR1B=0X0a;} //**********************************播放函数; void music_play(uint a[][2]){ const char Mtable[]=“Music Mode”; write_com(0X01); //清屏; for(int i=0;i<5;i++) { write_dat(Mtable[i]); } int i=0; char tem=aim,T=1; while((a[i][1]!=0)&&(tem==aim)&&state) { //A 返回 B 暂停 F 模式 C 上一曲你 D 播放 E 下一曲; num=key_in(); switch(num) { case 16: state=0; // F STATE = 0弹奏 break; case 15: aim=1; //下一首E break; case 14: pause=1; //播放D break; case 13: aim=0; ///上一首C break; case 12: pause=0; ///暂停B break; case 11: 第19页 北京邮电大学信息与通信工程学院 T=2; break;case 10: T=1; break;case 9: T=0;break;case 5: //变速,1代表正常速度A //慢速0 //快速9 //5 降调 S=0.5; break; case 6: S=1; break; default: break; } while(a[i][0]&&pause) { num=key_in(); if(num==12) { pause=0; } else { if(S == 0.5) m_sound(a[i][0]*S); else m_sound(a[i][0]); if(T==2) delay_ms(a[i][1]-100); else if(T==0) delay_ms(a[i][1]+100); else delay_ms(a[i][1]); i++; TCCR1A=0x00; TCCR1B=0X00; } } pause=0; //6 正常调 //加减速 //下一个音符; 第20页 北京邮电大学信息与通信工程学院 TCCR1A=0x00; TCCR1B=0X00; //中断,为下一个节拍做准备; } if(a[i][1]==0){ aim =(++aim)% list; } } /***************** 录制音乐函数; *****************/ void record(void){ write_com(0X01); const uchar R_table[]=“Recording Mode”; for(int i=0;i<9;i++){ write_dat(R_table[i]);} pause=1;while(pause){ uint Skey = key_in(); if((Skey>0)&&(Skey<11)) { int i=0;//count=0; while(i<10) { Skey=key_in(); OCR1A=0; TCCR1A=0x00; TCCR1B=0X00; if((Skey>0)&&(Skey<11)) { play(Skey); Ssong[i][0]=tone[Skey]; Ssong[i][1]=600; i++; delay_ms(20); } if(Skey==14) 第21页 //清屏;//开始录制 //先清零计数器 //录制完成,北京邮电大学信息与通信工程学院 按D键结束录制 { i=10; } } pause=0; //借助 PAUSE 来标记一下什么时候退出while } } } //***************************歌曲数据 uint music_data[][2]= { {440,400},{440,400},{659,400},{659,400},{740,400},{740,400},{659,800}, {587,400},{587,400},{554,400},{554,400},{494,400},{494,400},{440,800}, {659,400},{659,400},{587,400},{587,400},{554,400},{554,400},{497,800}, {659,400},{659,400},{587,400},{587,400},{554,400},{554,400},{497,800}, {440,400},{440,400},{659,400},{659,400},{740,400},{740,400},{659,800}, {587,400},{587,400},{554,400},{554,400},{494,400},{494,400},{440,800}, {0,0} }; // abcdefg uint music_1[][2]= {{262,400},{294,400},{330,400},{262,400},{262,400}, //乐谱 {294,400},{330,400},{262,400},{330,400},{349,400}, {392,800},{330,400},{349,400},{392,800},{392,300}, {440,100},{392,300},{349,100},{262,400},{392,400}, {440,300},{392,100},{349,300},{330,100},{262,400}, {294,400},{196,400},{262,400},{294,800},{196,400}, {262,400},{294,800},{0,0}};//music_1 int main(void){ INI_POTR(); //初始化 write_com(0X38); //显示光标等; write_com(0X01); //清屏; write_com(0X0f); //打开光标; write_com(0X06); write_com(0X80+0X02); for(int i=0;i<8;i++) 第22页 北京邮电大学信息与通信工程学院 { write_dat(table[i]); } write_com(0X80+0X11); delay_ms(5); while(1) { num = key_in(); if(num==16) //模式选择 { if(state==1) state=0; else state=1; } 放模式 if(state==1) { (state==1) { switchaim() { case 0: music_play(music_data); break; case 1: music_play(Ssong); break; default: break; }while delay_ms(10); } } else if(num==11) //录制模式; { record(); delay_ms(10); } else { write_com(0X01); 第23页 //播 北京邮电大学信息与通信工程学院 } const uchar Ptable[]=“playing Mode”; for(int i=0;i<7;i++) { write_dat(Ptable[i]); } while((num!=16)&&(num!=11)) { play(num); num=key_in(); } } } //弹奏模式 5.7实验结果: 实现了最初设想的功能,所设计的电子琴可以进行即兴弹奏、录制音乐、播放音乐以及音乐变速。测试图片如下: 第24页 北京邮电大学信息与通信工程学院 第25页 北京邮电大学信息与通信工程学院 接通电源后,显示屏以每次显示一个字符的形式显示出“HELLO WELCOM!”的欢迎文字,接着自动进入弹奏模式,并在LCD的第一行显示出“Playing Mode”的文字,用户每次按下按键都会在LCD的第二行的相应位置出现对应按键顺序的光标闪烁。在弹奏模式下,按下F键会进入播放模式,LCD显示出“Music Mode”字样,此时按下D键是播放/继续,按下B键是暂停,C键和E键分别代表上一首和下一首,9键则是将音乐速度调整为慢速,再次按下F键会回到弹奏模式。在弹奏模式下,按下A键会进入录制模式,此时LCD显示“Recording Mode”字样,可以使用1~0十个按键进行录音,想要听听录制好的音乐,可以切换到播放模式下进行欣赏。 六、排错过程: 基础题目训练阶段: 1.硬件连接好之后,在进行编程的过程中发现端口不够用,因为PB3和PD3这两个能产生中断的端口必须空出来作为暂停和开 第26页 北京邮电大学信息与通信工程学院 始按键的接口,于是我重新布线,将数码管显示小数点的右下角的引脚改接到PC0,同时在代码中将此端口设置为高电平输出,这样就解决了该问题。 2.当我们简单地把流水灯和计时器代码合并在一起然后编译运行时,却发现流水灯在工作,计时器却停止了工作。经过仔细排查,发现简单地将代码合并会导致单片机陷入流水灯的工作循环,而没有进入计时器的工作进程。经过一番思考,我们将流水灯的代码加以修改写入计时器的工作循环中,解决了计时器不工作的问题。 3.但是新问题又出现了,我们发现按下计时器的暂停按钮后,会导致流水灯也停止工作。经过小组的讨论,我们决定在中断程序函数里面加上流水灯工作的代码并加以修改使其能够在中断函数里面运行。经过多次调试,终于实现了计时器的计时、暂停、继续功能,并且流水灯能够一直工作不受计时器的暂停影响。 4.在调整计时器计时精读的过程中,我们发现本实验中使用的ATmega16频率不是16MHz,也不是1MHz,为了尽可能的实现秒表计时,试验了很多的数字组合,最后达到了30秒误差1秒的精确度,当然还可以达到更高的精确度。 电子琴设计与实现阶段: 1.在硬件连接的时候,没想到LCD液晶显示屏的每根管脚都需要 第27页 北京邮电大学信息与通信工程学院 连接,导致在进行程序下载验证的时候,显示屏总是不能显示出应有的文字,后来参考了相关文档资料发现是V0这个管脚也必须接地才可以,解决了问题。 2.在安插矩阵键盘的时候,费了很多功夫,首先,不知道哪根管脚是行线哪根管脚是列线,其次不知道所连接的端口的输出输入模式应该怎么设置,导致设计过程受阻,后来观看了视频并查阅相关资料解决了此问题。 3.在初步完成电子琴的弹奏功能程序时,我们开始对单片机进行测试,发现在按下数次按钮后单片机就会卡死,我们仔细检查了弹奏功能的代码,经过多次排查,我们小组最终将键盘检测函数key_in()和弹奏函数play()两条语句的执行顺序交换,以达到比较好的逻辑顺序效果,提高了程序的稳定性,把多次按下按钮会导致单片机卡死的问题给基本解决了。 4.播放音乐功能也是我们设想的一个重要功能。刚开始,按照我们的思路去实现该功能时,在测试时播放音乐是实现了,但是暂停和继续功能都没能够实现。我们小组对代码进行重新检查,检查出几个比较严重的逻辑错误。我们重新调整播放音乐函数的判断语句和循环结构,并加入一个pause变量来标志暂停状态,在按下暂停按钮时将pause标志为0,使程序退出播放循环。经过一番努力,我们顺利完成了暂停播放和继续播放的功能。 5.录制音乐功能的实现是整个实验过程里面最为困难的一环。我第28页 北京邮电大学信息与通信工程学院 们预先设想的实现方法是每按下一个按键,将对应音阶的数字和节拍存入数组中,然后录制完成后自动播放录制的音乐。但是,我们实际测试时发现录制的音乐并没有能自动播放。经过小组讨论,我们决定将录制好的音乐在播放音乐模式里面播放,根据这个思路,我们将录制的音乐对应的数组用播放音乐函数进行播放,成功地实现了录制音乐并播放的功能。 七、心得体会: 为期9天的单片机小学期圆满结束,不得不说,我从中学到了很多知识,从一个对单片机一窍不通的小白,蜕变成了一个熟悉单片机各个端口的作用和使用方法、懂得如何编程实现相应功能的技术人员。 在这九天中,我们通过观看老师给的视频资料和文档,加上查阅的资料,独立完成了所布置的任务。由于有C++的基础,加上有硬件的端口以及相应设备的使用说明文档的帮助,因此在我看来,在AVR Studio上进行C语言的编程从逻辑上比C++更容易理解,所需要的只是在编程时将端口的配置和逻辑函数结合到一起,实现编写的函数对单片机端口以及内部中断的控制。 第一天刚接到流水灯和数码管秒表计时器的任务的时候,内心真的十分激动,心想:实现了这个不就实现了街边广告牌上滚动的文字了么!但是一看到ATmega16芯片时还是傻了眼,心想:这么多的管脚都该怎么用啊?“视频里有”,同学告诉我,于是我就开始认真地 第29页 北京邮电大学信息与通信工程学院 研究起老师给的单片机教学视频和它的技术文档。由此发现,只需要将单片机的端口设置好,再套上一个循环结构,就可以实现流水灯的功能了。说做就做,于是最初的流水灯就实现了,可以一个一个依次循环点亮。那时真是好高兴!在做数码管的时候,由于不知道数码管的显示与管脚之间的关系,于是我先创建了一个数组,数组中的元素都是8位二进制数,其中只有一位是1,其余位都是0,如下: char a[8] = { 0b00000001,0b00000010,0b00000100,0b00001000,0b00010000,0b00100000,0b01000000,0b10000000 }; 然后我采用一个循环,将端口PORTX每次等于一个a[i],单步运行,找出了数码管的显示与管脚之间的对应关系。这样,之后的工作就轻松许多,只需要在该亮的位置将对应的PORTX端口置为1,就可以显示出自己想要的数字了。流水灯和数码管秒表计时器都分别完成了,最后只需将它们合在一起共同工作即可。不过这个过程也不是一帆风顺的,因为中断的概念我刚开始觉得很难理解,也不知道该将中断的有关函数放在代码的哪个位置,因此反复纠结反复研究视频和技术文档,持续了一段时间。后来我和同学决定将两份流水灯的程序,一份放在主程序main中,和秒表计时器的程序放在一起,即实现两者同时工作,且流水灯的闪烁间隔是一秒,另一份放在中断服务程序中SIGNAL()中,即实现按下按钮进入中断服务程序后,秒表计时器暂停 第30页 北京邮电大学信息与通信工程学院 工作,而流水依旧在依次循环闪烁。由此实现了流水灯和秒表计时器的独立工作,互不影响。 完成了基础题目的训练任务,我信心满满,迎来了我的下一个任务——电子琴。刚开始选题的时候觉得电子琴蛮有趣的,可以弹奏可以录音可以播放,而且原理看起来也比较简单。但是其实不是这样的,拿到元器件的时候,我发现,LCD液晶显示屏有16个管脚!矩阵键盘有8个管脚!但是有了前面对付ATmega16芯片的经验,我沉住气,查阅了有关LCD液晶显示屏和矩阵键盘的技术文档,以及一些经验之作,初步定下了键盘接到A端口,LCD的8个数据口接到B端口,D端口用于LCD的读写控制使能端以及扬声器的输入端。至此,硬件的连接工作就完成了,根据硬件的连接,我们开始了程序的编写。键盘检测函数、播放函数、液晶显示函数,弹奏功能,录制功能„„一步一步,一个完整的系统渐渐完善。由于有硬件,因此我们编写的程序可以马上下载到板子里验证效果,并及时修改,大大方便了我们排错和系统优化。期间由于JTAG下载器和AVR Studio总是出现连接失败的情况,浪费了我们许多宝贵的时间,个人总结原因是驱动可能用了一段时间会失效,解决办法是重新启动计算机,并将WINAVR这个环境卸载后再次装上,并且是装到与上一次不同的盘中,同时编译AVR程序的时候先接上JTAG下载器,试验了许多次,这个方法很管用,之后就没有出现该问题了。最终,电子琴的功能基本完成,并且达标,能实现弹奏、播放、录制、变速等最初设想的功能,但是可能还有一些小BUG没有调出来,导致电子琴在运行的过程中有不稳定的现象,第31页 北京邮电大学信息与通信工程学院 也不能排除是板子的问题。 最终,单片机小学期圆满结束了!9天的时间,完全的自己动手实验,不仅增加了自己对单片机的理解,提高了自己的编程能力,而且在这个过程中,我觉得团队的合作至关重要,自己连接的电路或者自己编写的程序,在自己看来都是对的,但是旁观者清,队友能很容易地帮你找出其中的错误;在和队友的讨论中,我能了解对方的想法和思路,多种想法和思路的碰撞能让我收获更多新的东西;组内的分工能让每个人都尽到自己的责任,发挥自己所长。 总之,这次单片机小学期是一次难忘的过程,一次丰富知识、提升技能的历程,也激起了我对单片机的兴趣,我今后会多多研究单片机,争取更上一层楼! 八、参考文献: 1.AVR C库函数介绍.pdf 2.AVR C语言开发入门指导.pdf 3.AVR单片机原理及应用.pdf 4.AVR高速嵌入式单片机原理及应用(修订版).pdf 5.深入浅出AVR单片机.pdf 6.1602液晶说明.pdf 7.AVR系统板说明.doc 8.cn_mega16-16L.pdf 9.EN_TC1602.pdf 第32页 北京邮电大学信息与通信工程学院 10.字符手册.pdf 11.百度百科《乐理》 12.AVR单片机软硬件设计视频教程-入门篇-第二讲-AVR硬件电路设计教程 13.AVR单片机软硬件设计视频教程-入门篇-第三讲-AVR开发基础知识 14.AVR单片机软硬件设计视频教程-入门篇-第四讲-C语言的流水灯验证 15.AVR单片机软硬件设计视频教程-入门篇-第五讲-按键与数码管的程序设计 16.AVR单片机软硬件设计视频教程-入门篇-第六讲-中断与定时器 九、意见与建议: 1.建议老师能稍微讲解一下实验室AVR软件的用法(视频中讲的是没有JTAG下载器的,与实验室不同,刚开始还以为是板子有问题); 2.实验室的元器件老旧,个别元器件特别是单片机芯片有问题之后,调BUG好久都不知道错在哪里,建议更新。 【AVR单片机C语言高级程序设计】推荐阅读: 单片机课程设计报警器07-13 《数字电路与单片机课程设计》课程设计报告11-01 单片机出租车计价器源程序05-24 单片机编程经验07-23 单片机编程心得10-12 单片机实习报告07-20 单片机说课稿10-11 单片机串口通信实验10-17 单片机工程师11-07 单片机开题报告图文11-16AVR单片机C语言高级程序设计 篇2
AVR单片机C语言高级程序设计 篇3
AVR单片机C语言高级程序设计 篇4
单片机C语言学习心得 篇5
如何学习avr单片机 篇6
PIC单片机C语言程序设计探析 篇7
AVR单片机C语言高级程序设计 篇8
AVR单片机C语言高级程序设计 篇9