C语言与语言混合编程DSP设计(共8篇)
1.C语言与语言混合编程DSP设计 篇一
关于c语言编程中八皇后问题的设计报告
一、课题的来源及意义
八皇后问题是一个古老而著名的问题,该问题是十九世纪著名的数学家高斯1850年提出的。
在国际象棋中,皇后是最有权利的一个棋子;只要别的棋子在它的同一行或同一列或同一斜线(正斜线或反斜线)上时,它就能把对方棋子吃掉。所以高斯提出了一个问题:在8*8的格的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一列、同一行、或同一条斜线上面,问共有多少种解法。
到了现代,随着计算机技术的飞速发展,这一古老而有趣的数学游戏问题也自然而然的被搬到了计算机上。运用所学计算机知识来试着解决这个问题是个锻炼和提高我自己编程能力和独立解决问题能力的好机会,可以使我增强信心,为我以后的编程开个好头,故我选择了这个有趣的课题。
二、面对的问题
1)解决冲突问题:这个问题包括了行,列,两条对角线; 列:规定每一列放一个皇后,不会造成列上的冲突; 行:当第I行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以I为下标的标记置为被占领状态;
2)使用数据结构的知识,用递归法解决问题。
三、需求分析
1、涉及到的知识
本次设计中,用到的主要知识有:递归法的运用,for语句的灵活运用,数据结构中树知识的灵活运用、栈及数组的掌握。
2、软硬件的需求
1)系统要求:winxp以上操作系统; 2)语言平台:tc++或vc++6.0;
3、功能需求
当运行程序时,在屏幕上显示每一种方法八个皇后的相对位置,要用比较直观 的界面显示。
四、概要设计
我的思想是用循环递归循环来实现的,分别一一测试了每一种摆法,并把它拥有的92种变化表现出来。在这个程序中,我的主要思路以及思想是这样的:
1)解决冲突问题:
这个问题包括了行,列,两条对角线;
列:规定每一列放一个皇后,不会造成列上的冲突; 行:当第I行被某个皇后占领后,则同一行上的所有空格都不能再放皇后,要把以I为下标的标记置为被占领状态; 对角线:对角线有两个方向。在这我把这两条对角线称为:主对角线和从对角线。在同一对角线上的所有点(设下标为(i,j)),要么(i+j)是常数,要么(i-j)是常数。因此,当第I个皇后占领了第J列后,要同时把以(i+j)、(i-j)为下标的标记置为被占领状态。
2)数据结构的实现
而对于数据结构的实现,学生则是着重于: 数组a[I]:a [I]表示第I个皇后放置的列;I的范围:1..8;对角线数组:b[j](主对角线),c[j](从对角线),根据程序的运行,去决定主从对角线是否放入皇后;
五、详细设计和实现
1、算法描述
A、数据初始化。
B、从n列开始摆放第n个皇后(因为这样便可以符合每一竖列一个皇后的要求),先测试当前位置(n,m)是否等于0(未被占领)。如果是,摆放第n个皇后,并宣布占领(记得姚横列竖列斜列一起设置),接着进行递归;如果不是,测试下一个位置(n,m+1),但是如果当n<=8,m=8时,发现此时已无法摆放时,便要进行回溯。从问题的某一种可能出发,搜索从这种情况能出发,继续搜索,这种不断“回溯”的寻找解的方法,称为“回溯法”。
C、使用数组实现回溯法的思想。D、当n>8时,便打印出结果。
E、输出函数我使用printf输出,运行形式为:第m种方法为:* * * * * * * *
2、算法流程图
六、代码编写及详细注释
#include
void main()/*----------------------------Main:主函数。----------------------------*/ { system(“title 叶青--递归算法八皇后问题 ”);cout<<“ ”<<“八皇后的解法:”< { Output();return;} for(i = 1;i <= QUEENS;i++)//!n还没到8,在第n行的各个行上依次试探。 { Site[n] = i;//!在该行的第i行上放置皇后。 if(IsValid(n))//!如果放置没有冲突,就开始下一行的试探。 Queen(n + 1);}} int IsValid(int n)/*------IsValid:判断第n个皇后放上去之后,是否合法,即是否无冲突。------*/ { int i;for(i = 0;i < n;i++)//!将第n个皇后的位置依次于前面n-1个皇后的位置比较。 { if(Site[i] == Site[n])//!两个皇后在同一列上,返回0。return 0;if(abs(Site[i]i))//!两个皇后在同一对角线上,返回0。return 0;} return 1;//!没有冲突,返回1。} void Output()/*------------Output:输出一个解,即一种没有冲突的放置方案。------------*/ { int i;printf(“No.%-5d” , ++iCount);//!输出序号。 for(i = 0;i < QUEENS;i++)//!依次输出各个行上的皇后的位置,即所在的列数。printf(“%d ” , Site[i]);printf(“n”);} 七、程序调试 调试过程、步骤及遇到的问题 在完整程序调试时遇到几个小问题,后经细心改正后才把调试工作做完。 例如:当用printf输出时,出现了一些错误,几经调试后,发现原来是缺少了stdio.h这样一个头文件,添加了头文件后, 还出现了一些问题,逻辑错误导致程序死循环或不循环或循环一小部分,但是编译时却没有错误,就是没有正确的输出答案,一开始我也不知道是怎么回事,通过和同学的交流,发现是逻辑错误,经过改正后,程序终于可以运行了.八、运行与测试 运行演示 九、总结 在这次的程序设计,我从中得到了许多的经验以及软件设计的一些新的思路;从这个八皇后问题设计以及分析中,本人从中理解到了数据结构对于计算机软件设计的重要性,它的使用,可以改变一个软件的运行周期,也可以将软件的思路从繁化简,并且都能够通过数据结构的相关引导,将本身以前编程思想进行扩充,发展;这也是在这次课程设计中我所掌握得到的。 但由于我的基本知识还不是那么扎实,也缺乏对软件设计的经验,在这过程中也出现了一些问题,如,八皇后在变成初期由于没真正体会到数据结构中“树”在里面的运用,将程序往大一时c语言的方向发展,不自觉的采用了非递归的算法,结果大大增加了程序的复杂程度。并且也让整个程序的时间复杂度变得更大;在后来学生对数据结构的第六章进行了比较深入的研读,才发现了数据结构树的实际运用的空间是相当的大,并且,通过了重温树的回溯,以及二叉树的遍历,最终将程序进行了一次较大的改造。并且通过思考,再将以前的数组知识加以运用才最终解决了这个问题,整个程序的算法的可看性也有了相当的改进。 以前对数据结构的学习还是具有相当大的意义,它从一个程度上改变了我们的编程思想,如何将一个程序快速而又准备的进行编写,进行编译,都成为了我们思考的重点,也通过这一门课的学习,我们将数据结构的思想带入到了我们以后的编程学习中去。在这个阶段,我也明白了,好的思想,不能提留于字面上的认知,还需要的是平时多练多写一些相关的程序,并且通过修改,加入新的算法去尝试改变自己的一些编程思想。保持更新算法的速度,这才是关键。 我觉得还可以考虑开发N皇后问题,在主界面中添加一个 int型的变量,程序一开始要求输入一个数(确定是几皇后问题),输入后按下 enter 后,输出各种解.主程序与八皇后的求解大体相同.十、参考文献 [1]苏仕华,数据结构课程设计.-北京:机械工业出版社,2005.5 [2]于永彦,赵建洋.课程设计指导书.淮安:江苏淮阴工学院 计算机工程系,2006 [3]刘振安,刘燕君,孙忱.C++语言课程设计.北京:高等教育出版社,2003 [4]陈志泊, 张海燕, 王春玲.Visual C++程序设计.中国铁道出版社 ,2005 [5]吕凤哲,C++语言程序设计(第二版).北京:电子工业出版社,2005 [6]殷人昆,陶永雷等.数据结构(用面向对象方法与C++).北京:清华大学出版社,1999 [7]严蔚敏,吴伟民,数据结构.北京:清华大学出版社,1997 [8]李春葆.数据结构—考研指导.北京:清华大学出版社,2002 [9]陈慧南.数据结构—C++语言描述.北京:人民邮电出版社,2005.03 关键词:C,汇编语言,调用 1 引言 C语言是一种介于高级与低级之间的中级语言,以其数据类型丰富、语句精炼灵活、效率高,表达力强以及可移植性好等诸多优点,成为目前倍受欢迎的一种编程语言。它有丰富的库函数,也可以使用BIOS和DOS的中断功能调用,完成许多由汇编语言完成的工作。但在对速度要求较高的场合,以及在访问计算机系统的硬件资源或接口地址的读写等方面,却显示出了明显的不足。汇编语言作为一种符号语言,具有代码短,占用内存空间少,装载运行速度快,并能对硬件资源进行直接控制等优点,对位、字节和地址进行操作的功能,成为最受欢迎的编程语言之一。但其编程工作量大,开发周期长,容易出错且不宜调试。事实上没有一种编译程序所产生的目标代码能够像汇编程序那样高效和紧凑。大多数情况下,这种小差别无关紧要,但在某些特殊情况下,对程序的空间和时间要求很高的场合,如浮点数计算软件包就是用汇编语言写的,因为它使用频繁,并且很大程度上影响着使用这些程序的执行速度。所以有时需要使用汇编语言编写程序,来满足应用程序中局部的特殊要求。使用C语言和汇编语言混合编程,两种语言的程序相互调用,进行参数传递,共享数据结构及数据信息,这样能充分发挥各语言的优势和特点,提高程序的运行速度和效率以及应用软件的效率。基于上述情况,将两者有效结合,混合编程,扬长避短,是一种行之有效的程序设计开发方法。 2 混合编程的调用规则 (1)参数传递的次序与它们出现的次序是相反的。 (2)传递完参数后,C语言还将保存(CS,IP)。如果C语言是SMALL或COMPACT存储模式下编译的(或者过程是NEAR型的),那么只保存IP,而在MEDIUM、LARGE或HUGE模式下编译的(或者过程是FAR型的),那么CS和IP都会被压入堆栈,其顺序是CS在前,IP在后。不过这个过程是C语言自动进行的而不需要干预。 (3)还有BP也必须保存在堆栈中,然后才可以通过BP和偏移地址来访问参数。 (4)最后一条指令应当是后面不带数字的RET,因为堆栈到原始位置的工作将由C程序重新获得控制权以后才会执行。 (5)任何与C语言共享的名称都必须在前面加下划线,而且C语言只识别前8个字符。 (6)对于普通的参数C语言传递的是参数值,而对于数组,传递的是指针(也就是数据的地址)。 (7)如果C语言是在MEDIUM、LARGE或HUGE模式下编译的,那么汇编语言过程应该设为FAR型;C语言是SMALL或COMPACT存储模式下编译的,那么汇编语言过程应该设为NEAR型。 不过在MASM5.1或TASM1.0及更高的版本的情况下就不必担心偏移地址、在共享名称前加下划线并保存BP这些琐事,因为它们可以由编译器自动完成。 3 汇编语言中调用C语言函数 内嵌汇编不用单独编辑汇编语言文件,比较简洁,但是有诸多限制,当汇编语言的代码较多时一般放在单独的汇编文件中。这时就需要在汇编语言和C语言之间进行一些数据的传递,最简便的办法就是使用全局变量。在汇编语言中调用C语言的函数,需要在汇编中IMPORT对应的C语言的函数名,然后将C语言的代码放在一个独立的C语言文件中进行编译,剩下的工作由连接器来处理。 mingw编译系统在所有C语言符号前加了一个下划线前导符。所以在汇编代码中要用extern指令进行特殊处理。还是用实例来说明比较直观。假设分别建了两个文件,一个是Calc.c,另一个是Call Calc.asm,两个文件中各有一个函数。 Calc.c中内容为: Call Calc.asm中的内容为: add()函数接受两个整型参数,相加后返回给调用者,返回值按照C语言调用约定存放在EAX寄存器中;在汇编代码中要先要用extern关键字将_add声明为外部符号,然后才能在程序中使用。这里只需要知道C的符号规则是要加一个前导下划线就可以了。在调用的地方用的也是call_add。 4 在C语言中调用汇编 4.1 汇编函数 在C语言中调用汇编文件中的函数,要做的主要工作有两个,一是在C语言中声明函数原型,并加extern关键字;二是在汇编中用EXPORT导出函数名,并用该函数名作为汇编代码段的标识;最后用mov pc,lr返回。然后,就可以在C语言中使用该函数了。从C语言的角度,并不知道该函数的实现是用C语言还是汇编。更深的原因是因为C语言的函数名起到表明函数代码起始地址的左右,这个和汇编的label是一致的。 在这里,C语言和汇编语言之间的参数传递是通过AT-PCS的规定来进行的。简单地说就是如果函数有不多于4个参数,对应的用R0-R3来进行传递,多于4个时借助栈,函数的返回值通过R0来返回。 4.2 汇编代码 在C中调用汇编代码规则: (1)内嵌的汇编语句可以用“;”结束,也可以用换行符结束,一行中可以有多个汇编语句,相互间用“;”分隔,但不能跨行书写。 (2)必须使用C语言的注释分隔符“/*”和“*/”。 (3)将masm.exe宏汇编程序拷贝到Tubro C目录下,并重命名为Tasm.exe。 (4)对内嵌汇编指令的C源程序进行编译、连接,格式为:TCC.B.XXX文件名库文件名。 其中,XXX为库文件所在目录的路径,文件名是内嵌汇编指令的C源程序的文件名。 (5)在汇编语言中使用寄存器时,不区分大小写,且只能是8086提供的寄存器名,但在C程序中使用汇编语言的寄存器时,要用大写且前面加一个下划线。 假设有两个文件,一个是Simple Ret.asm,一个是Call Asm.c。 运行结果将会打印1。 所有的要点就是C语言调用约定和global关键字以及extern关键字的使用,global将符号导出给链接器extern声明外部的符号。 5 结语 C语言与汇编语言混合编程,彼此相互调用,进行参数传递,共享数据结构及数据信息,是一种有效的编程方法,但在实际运用中要注意内存模式以及寄存器的分配给程序带来的影响,并且还应考虑到这样做可能会丧失源程序的可移植性。所以,在具体开发设计阶段,应该综合考量各语言的特点,权衡利弊,才能设计出优秀的程序。 参考文献 [1]谭浩强.语言程序设计.第二版[M],北京:清华大学出版社,1999. [2]沈美明,温冬蝉编著.IBM-PC汇编语言程序设计[M].北京:清华大学出版社,1994. [3]孙振业,史宝慧编著.C语言及应用.电子科技大学出版社,1999. 【关键词】C语言;DSP程序;main()函数 传统的汇编语言依赖于计算机硬件,程序的可读性和可移植性比较差。一般的高级语言具有很好的移植性,但是又难以实现汇编语言的某些功能。而C/C++语言作为一种高级语言,既可以访问物理地址又可以进行位操作,能直接对硬件进行操作,适合用作DSP开发语言。 1、C语言的基本结构 一個最小的C应用程序项目至少包含如下几个文件: (1)有且必须有一个作为C程序入口点的包含main﹙﹚函数的C语言源文件(.C)。系统库初始化完毕后,就把控制权交给main﹙﹚函数。 (2)连接命令文件。该文件包含了DSP和目标板的存储空间的定义以及代码段、数据段是如何分配到这些存储空间的。 (3)C运行库文件rts2xx.lib。C运行库提供了编译器提供的所有功能,包括初始化C语言环境、设置堆栈及提供标准C的库函数如printf等。库文件及其源代码位于CCS安装目录下的\c2000\cgtools\lib目录下。 若用户所写程序要写进ROM存储器并在上电后直接运行,还必须包含中断向量表文件,中断向量表文件通常是汇编文件(.asm)的形式,此文件需要被链接器命令文件准确定位在DSP复位后执行指令的地址。 一个用C编写的DSP程序的常规执行流程为:中断向量表的第一条指令可设置为“B_c_int00”,从而在上电复位后,把控制权交给rts2xx.lib运行库中的C环境入口点_c_int00,在c_int00()函数中完成堆栈指针的初始化及全局变量初始化等操作,再调用main()函数,把控制权交给main()函数,从而执行用户的应用程序。 2、C程序中CMD文件 TI的CCS开发环境提供了将C语言编译为汇编语言的C/C++编译器。与汇编器类似,C/C++编译器对C程序编译后也产生已初始化段和未初始化段,具体的段名稍有不同。 C/C++编译器不会生成.data段,但也产生了一些新的段。 TMS320C2xx的C/C++编译器生成以下几种段。 (1)包括数据表或可执行代码的初始化段。编译器生成以下几种初始化段。 .text段:包括所有的可执行代码和常量。 .cinit 段:包括初始化数量和常量的表。 .const段:包括字符串常量、明显初始化的全局和静态变量的定义和初始化。 .switch段:包含Switch语句表。 (2)用于保留空间的未初始化段。程序可在运行时使用这些空间建立和存储变量。编译器生成以下几种未初始化段。 .bss段:为全局和静态变量保留存储空间。若设置了-c连接选项,C的引导程序会将数据从.cinit段复制到bss段。 .ebss段:与bss段类似,只为far修饰的全局和静态变量保留存储空间。若设置了-c链接选项,C的引导程序再将数据从cinit段中复制到edss段。 .stack:段:系统堆栈段,通过堆栈可以给函数传递参数或为局部变量分配空间。 .sysmem段:为动态存储器分配保留空间。函数malloc()、calloc()和realloc()使用该保留空间。若程序没有使用这些函数,不会产生.sysmem段。 .esysmem段:与.sysmem段类似,只为far修饰的malloc()、calloc()和realloc()才能使用该保留空间。若程序没有使用这些函数,不会产生.esysmem段。 链接器将不同模块中同名段组合为输出段,一个完整的程序就是由这些输出段组成。用户可以将这些输出段分配到特定的地址空间,以满足系统需要。 通常.text、.cinit和switch段会被链接到ROM或RAM,且必须分配到程序存储器;.const段被链接到ROM或RAM,且必须分配到数据存储器;.bss/.ebss、.symsmem/.esysmem段必须被链接到RAM,且必须分配到数据储存器中。 使用#pragma伪指令,也可以在C程序中自定义代码段和数据段,#pragma是标准C中保留的预处理命令,它告诉编译器的预处理器如何处理函数和数据。#pragma必须在符号被定义和使用前使用,且不能在函数体内声明#pragma。 CODE-SECTION pragma伪指令函数在指明的段中分配空间,使用该伪指令创建的段可与.text段分配到不同的区域。它的语法为: #pragma CODE-SECTION(func,“section name”) 其中func为函数名,section name是用户自己定义在程序空间的段名。 3、C编程的其他问题 (1)关键字 与标准C一样,DSP的C编译器也支持关键字,下面对常用的关键字进行介绍。 1)const关键字。DSP的C/C++编译器支持ANSIC中的const关键字,用于限定值不能被修改的变量或数组。若变量或数组被const关键字所修饰,则该变量或数组所占的存储空间会被分配到.const段。 2)volatile关键字。使用volatile关键字修饰的变量每次被访问时,执行部件都会从其所在的内存单元中取出值。而未使用volatile修饰的变量在访问时则可能直接从CPU的寄存器中取值,因为该变量之前可能被访问过,读取寄存器的速度比读取内存要快得多。使用volatile修饰的变量会被分配到末初始化段中。程序设计时,那些随时可能被外部硬件改变的内存地址的内容要使用volatile修饰,如芯片内部的外设寄存器或某个随时可能改变的外部硬件的寄存器。 3)crgister关键字。使用crgister关键字可用高级语言直接访问DSP的控制寄存器,但crgister修饰的对象的名字要与C28x DSP的控制寄存器名相符,否则编译器会报错。该关键字不能在函数内部使用,且只能修饰整型或指针变量,而不能修饰浮点型及任何结构体及共用体。 4)interrupt关键字。interrupt关键字用于指定一个函数作为中断服务函数。使用该关键字指定一个函数后,编译器会按照中断服务函数的要求对寄存器进行保护并使用正确的返回顺序,函数的入口参数必须是void类型,函数返回值也必须是void类型,函数体内使用局部变量,也可自由是堆栈和全局变量。 (2)C运行支持库 同标准C一样,C28x的开发也可使用库函数来实现常用任务。C运行支持库的库文件位于\C2000\cgtools\lib,该库文件包括标准的C/C++运行支持库函数、浮点运算函数、I/O函数及程序的入口点c_int00等。在CCS的安装目录\C2000\cgtoo\lib中有库对应的源程序文件rts.src,用户可以利用归档器和建库器对rts.src中的文件进行提取、修改等操作,并重新生成自己需要的库文件。 参考文献 [1]王玮,万隆.DSP原理与实例应用[M].北京:清华大学出版社,2011年6月 [2]杨东凯.DSP嵌入式系统设计与开发指南.北京:中国电力出版社,2008年 题目01:在一个已知的字符串中查找最长单词,假定字符串中只含字母和空格,空格用来分隔不同的单词。 [cpp] view plain copy print? 1.2.3.4.5.6.7.8.9.int main(){ // 用数组定义一个字符串 char array[50] = “zha junju zhamengjun z mengjun”; char *str = array;// 定义指针变量str,指向数组array int len = 0;// 定义变量len,用于计数 int max = 0;// 定义变量max,存放最长单词的长度 char *p = 0;// 定义指针变量p,指向最长单词的首字符 10.11.// 判断指针当前指向的字符是不是' 12.while(*str!= ')13.{ 14.if(*str!= )// 判断字符是不是空格 15.{ 16.len++;// 计数加1 17.18.// 判断最大长度跟len长度的大小 19.if(max < len){ 20.max = len;// 如果max小于len,将len赋值给max 21.p = str1]; 46.} 47.else 48.{ 49.sumDaysOfMonth += pingYear[monthDay;// 定义整型变量days,存储一个月内相隔的天数 54.int sumDays = 0;// 定义整型变量sumDays,存储两个时间点相隔的总天数 55.56.// 得到两个时间点相隔的总天数 57.sumDays = sumDaysOfYear + sumDaysOfMonth + days;58.59.printf(“两个时间点相隔%d天n”, sumDays);60.61.// 根据相隔的天数,判断小明遇到的人 62.if((sumDays % 2 == 0)&&(sumDays % 3 == 0))63.{ 64.printf(“小明既结识了帅哥又结识了美女!n”);65.} 66.else if(sumDays % 2 == 0)67.{ 68.printf(“小明结识了帅哥!n”);69.} 70.else if(sumDays % 3 == 0)71.{ 72.printf(“小明结识了美女!n”);73.} 74.else 75.{ 76.printf(“小明没有结识帅哥和美女n”);77.} 78.} 心得体会:(1)利用for循环遍历,if条件来判断是平年还是闰年,求出相隔年数的累加的天数(2)同理,利用第一步的方法,求出相隔月数的累加的天数,只是要注意每月的天数,根据平年和闰年的不同分别保存在两个不同的数组中,以便利于累加 (3)将输入的日减1,计算出当月相隔的天数,最后求出两个日期相隔的总天数。(4)根据总天数取余2和3,判断出小明当天结识的是美女还是帅哥。 题目05:提示用户输入一个正整数n,利用while循环计算并输出:1-2+3-4+5-6+7…+n的和。 [cpp] view plain copy print? 1.2.3.4.5.6.7.8.9.int main(){ // 1.定义变量存储用户输入的整数 int n = 0; // 2.判断n是否为正整数 while(n <= 0){ // 2.1 提示输入 printf(“输入一个正整数:n”); 10.11.// 2.2 让用户输入 12.scanf(“%d”, &n);13.} 14.15.// 3.计算阶乘 16.int sum = 0;// 存储计算结果 17.int current = 0;// 当前要累加的数值 18.while(current < n){ 19.current++;20.21.// 如果是偶数,就减 22.if(current % 2 == 0){ 23.sum-= current;24.} else { // 如果是奇数,就加 25.sum += current;26.} 27.} 28.29.// 4.输出结果 30.printf(“%dn”, sum);31.32.return 0;33.} 心得体会: (1)确保从键盘上输入的是一个整数(用while来判断);(2)用while循环来遍历从1到n的值; (3)通过奇偶性判断所要累加数值的正负性,奇数就累加,偶数就累减。 题目06:提示用户输入一个正整数n,计算并输出n的阶乘结果:1*2*3*…*n。 [cpp] view plain copy print? 1.2.3.4.5.6.7.8.9.int main(){ // 1.定义变量存储用户输入的整数 int n = 0; // 2.判断n是否为正整数 while(n <= 0){ // 2.1 提示输入 printf(“输入一个正整数:n”); 10.11.// 2.2 让用户输入 12.scanf(“%d”, &n);13.} 14.15.// 3.计算阶乘 16.int result = 1;// 存储计算结果 17.int current = 1;// 当前的乘数 18.while(current <= n){ 19.result *= current;// 累乘每次的乘数 20.current++;// 乘完一次就++ 21.} 22.23.// 4.输出阶乘结果 24.printf(“%d!= %dn”, n, result);25.26.return 0;27.} 心得体会: (1)可以利用for循环或者while循环进行遍历,利用累乘即可求出值。(2)还可以利用递归来做,更简单。 题目07:编写一个函数,判断某个字符串是否为回文。回文就是从左边开始读 和 从右边开始读 都是一样的,比如“abcba” [cpp] view plain copy print? 1.2.3.4.5.6.7.8.9.int main(){ printf(“%dn”, isHuiwen(“a”)); return 0;} /* 返回1代表是回文 返回0代表不是回文 10.*/ 11.int isHuiwen(char *str) 12.{ 13.// 1.定义一个指向变量left指向字符串的首字符 14.char *left = str; 15.// 2.定义一个指向变量right指向字符串的末字符 16.char *right = str + strlen(str)1)+ count(n);// 求出每一个阶乘的累加和 58.} 59.60.// 定义和求出一个累加和 61.int count(int n) 62.{ 63.if(n == 1)64.return 1; 65.return count(n1;22.23.// 如果左边元素的下标 < 右边元素的下标 24.while(left < right)25.{ 26.// 利用中间变量交换两个元素的值 27.int temp = array[left];28.array[left] = array[right];29.array[right] = temp;30.31.// 交换一次后,左边元素下标增加,右边元素下标减小 32.33.left++;34.right--;35.} 36.} 心得体会: (1)首先要明白一点,为什么不能通过sizeof(array)/ sizeof(int)来求出数组元素的个数?因为当数组作为参数传递的时候,函数的参数array实际上当做变量来存储传来的数组首元素的地址。而每一个指针变量占用8个字节。 (2)分别拿出数组首元素和数组尾元素,然后利用中间变量交换两个元素的值。(3)利用while循环,遍历数组元素,并使left< right保证循环到中间即可,否则每个元素又进行一次交换,结果值没有改变。 2.a、写中断程序一定要用using语句指定寄存器组。第1、2、3组都可以,不能是0,否则可能会main()函数冲突。从一个中断程序中调用函数必须和中断使用相同的寄存器组(摘自《Keil Cx51 编译器用户手册中文版》P129)。建议把原本中断函数需要调用的函数直接写在中断函数里,无须调用。 b、51单片机的中断有两个优先级。一个中断不会打断另一个相同优先级的中断。这样相同级别中断可以使用同一个组。比如:低优先级的中断函数都用 using 1,高优先级的中断都用 using 2。这样不会冲突。 3.C语言无符号数容易犯的错误。若定义成有符号数char,则不会陷入死循环。 main(){ unsigned char i;for(i = 2;i>=0;i--){ printf(“%d”,i);} } 4.C51忌讳使用绝对定位_at_,因为只要定义变量和变量的作用域,编译器就会把一个固定地址给这个变量,无须人工将其绝对定位,这样可能引发其他问题。 5.bit与sbit的区别:bit定义的位标量的地址是随机的,而sbit定义的位标量的地址是确定的。bit只能访问芯片内部RAM中的可寻址位20H-2FH,而sbit可以访问芯片内部RAM中的可寻址位和特殊功能寄存器中的可寻址位。注意不能直接在程序里用P1^0等位变量,需要经过sbit定义才可以使用。例如: bit tem;sbit led=P1^0;tem的地址是随机分配的,而led的地址则固定为0x90.0。sbit变量后面需要跟等号=。6.为了避免由于使用参数宏而带来意外的错误,需要注意以下几点: 6.1 宏的参数必须带括号,例如 #define CIRCLE_SQUARE(R)3.141*(R)*(R)6.2 对所使用的参数宏进行简单地展开检查; 6.3 使用简单表达式、对参数加括号、避免节外生枝的使用方式(例如“++”、“--”一类都属于不必要的附件运算); 6.4 在参数宏定义时,对于运算顺序通过括号进行明确的限定,只要遵循以上几点,就可以避免大多数应用场合的意外错误。 手把手教你写程序 内容:从最简单的程序入手,手把手教你写程序,让同学们拿到一个复杂的程序或者任务,能快速找到切入点,写出程序,再在此基础上优化程序。当拿到一个单片机任务时,不要急于动手写程序,先仔细分析它的以下几个点: 1、它要单片机整体实现什么功能 2、功能细分(模块化),先干什么,再干什么,最后干什么 3、画初步流程图,(把几个模块画出即可) 4、模块之间的分析:一个模块到另一个模块之间,怎么变换,怎么连接(优化流程图) 5、单个模块分析:每个模块要做什么(流程图细化) 6、所有模块结合连接,细化所有流程图 7、分析单个模块每步要用到的方法或者指令 8、总流程图定型 9、纸上写程序,对照流程图分析其可行性,若不可行则返回 10、上机调试,加注释 11、从小到大,一个功能一个功能地调试; 以上十一步,缺一不可(小程序例外)切记:流程图的确定很重要,需反复修改 大忌:拿到任务,不仔细分析就写程序。即使是小程序,我们也要养成良好的编程习惯,不要一味的追求结果。写小程序可能比别人快,若是大程序,一旦出现思维混乱,或者出现程序调试不出结果,那么你花在调试上的时间,要比别人的多。!!!磨刀不误砍柴工!!!程序的优化:属于后期工作,只有调试出来后,才去优化,如果一开始优化和写程序同时进行,一是加重你的思考量,二是出现问题无从下手。无疑增加了写程序的难度。对于一个初学者,写一个程序,本身头脑就处于紧张的状态,思考的问题就很多,如果此时把优化程序也考虑进去,你脑袋的负荷无疑加重,若你头脑精明,你可以把优化的地方,先在纸上记下来,等到调试结果正常,再把你想到的,优化的地方加进去。 7、如果在中断程序中改变了多字节类型的变量,那么中断程序以外的程序中(主程序,子函数)要使用该多字节类型变量的话,读写前要关中断,读写后再开中断。否则会导致偶尔读写错误。(实质为资源冲突)举一反三: 其他的数据类型也可能有这种影响。例如:长整型、浮点型。例如: unsigned int ms_counter;void T0(){ //定时器程序每100毫秒中断一次,程序略 if(ms_counter<1000)ms_counter++;} void main(void){ //初始化定时器程序每100毫秒中断一次,程序略 unsigned char tt;ms_counter=0;tt=0;//用tt控制只响一次 while(1){ if(ms_counter<400){ if(tt==0){ tt=1;Sound_on(); } } else { Sound_off();} //其他程序 } } 8、sbit变量不能使用extern关键字,使其在不同的文件中被使用,如要在led.c和main.c文件中使用同一个变量led0,有以下下两种办法: 1.在各种文件中重复定义变量,如在led.c中定义sbit led0=P1^0;同样在main.c中定义sbit led0=P1^0;这样,led0就变成了全局变量,可以在两个文件中使用。 2.将sbit led0=P1^0定义到led.h头文件中,均在led.c和main.c中包含led.h这个头文件。 9、在多文件的程序中声明外部变量(extern和) 如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分别在两个文件中各自定义一个外部变量Num,否则在进行程序的连接时会出现“重复定义”的 错误。正确的做法是:在任一个文件中定义外部变量Num,而在另一个文件中用extern对Num作“外部变量声明”。即extern Num;注意若Num为uchar类型,应当写为“extern uchar Num”,否则会当为int,而导致出错。 当使用static声明变量和函数时,需要在定义变量和函数的基础上加上此关键字,而不能单独使用。例如: static int a;//定义性声明,需要时,直接使用变量a即可 a = 0x01; static int funA(int a, int b);//声明,且static不起作用 int funA(int a ,int b)//定义,即使funA有static关键字修饰,但由于static不能单独使用,//故funA仍为外部函数。 { …… } extern对变量进行声明时,如没有初始化,则为引用性声明,不含定义,如需使用此变量,需要进行定义。例如: extern int a;//引用性声明,不含定义 extern int a = 0x01;//定义性声明,需要时,直接使用变量a即可 int a;//定义 extern对函数进行声明时,如没有函数体,则为引用性声明,不含定义。 extern int funB(int a ,int b);//引用性声明,不含定义,且extern声明可以省略 extern int funC(int a, int b)//定义性声明 { …… } 10、一般的,要尽量减少中断服务程序的内容和长度。因为在主程序中可以还需要随时响应其他的中断或事件。如果一个中断服务程序过程,很可能会影响到主程序对外部信号的检测和响应。通常,在中断程序中只是改变一些变量或标志位,在主程序中再根据变量或标志位的值进行判断,处理相应的事件。 11、在A/D和D/A转换电路中,电源电压和基准电压的稳定性,对转换的精度影响很大。另外,A/D和D/A转换电路中要特别注意地线的正确连接,否则转换结果将是不正确的,干扰影响将很严重。 12、根据C语言标准,左移“<<”和右移“>>”运算要求操作数至少是int,如果不满int,自动转换成int(C语言整型提升)。因此 uchar a=0x01;a<<8;实际运算,并不是8位数左移8位,而是int型左移8位。 13、在中断里调用其他函数,且要进行参数传递时,必须保证被调用函数所使用的寄存器组与中断函数一样,否则会产生不正确的结果。为了保证被调用的函数与中断函数使用的寄存器一致,可对被调用函数使用using,不过此函数只能被中断函数调用。 14、函数不使用using 时,所使用寄存器组保持与此函数被调用前相同,不对RS0和RS1的值进行修改;当使用了using 关键字后,此函数所使用的寄存器组与using所定义的一样。 15、当指定中断程序的工作寄存器组时,保护工作寄存器的工作就可以被省略。使用关键 字using 后跟一个0 到3 的数对应着4 组工作寄存器当指定工作寄存器组的时候默 认的工作寄存器组就不会被推入堆栈这将节省32 个处理周期,因为入栈和出栈都需要2 个处理周期。为中断程序指定工作寄存器组的缺点是所有被中断调用的过程都必须使用 同一个寄存器组否则参数传递会发生错误。 16、如何使用pdata 类型的变量?当要使用到pdata 类型的变量,如下: void main(void){ uchar pdata a;a=0x01;} 则需要进行如下设置,否则pdata 的变量a则会无效。 a、修改STARTUP.A51的内容。默认时,PPAGEENALBE为0,表示不允许pdata类型的变量,须将其值改为1;PPAGE表示pdata类型的变量存储在哪一页,01H表示存放在外部存储器的第1页,地址范围100H至1FFH,此时P2经STARTUP.A51处理后的值为0x01;此项设置需和BL51连接器的设置一致。 b、修改BL51连接器。根据STARTUP.A51中PPAGE所设置的值来填写Pdata的值,如下图。图中Pdata的值可以填写100H至1FFH中任意一个,表示pdata类型的变量从所填 写的值开始存储。例如,当Pdata填写的值为108H时,表示pdata类型的变量从108H开始存储,因此,存储范围变为了108H至1FFH。 另外,存储模式Compact的作用是将没有指定存储类型的变量定义为pdata类型,对uchar pdata a;变量的定义没有影响,但对uchar a;则有影响。 17、XBYTE的用法。XBYTE存在于#include 头文件中。 XBYTE[0x000F]=data; // 此语句表示将data写到外部RAM中的0x000F data=XBYTE[0x000F] // 此语句表示读取外部RAM中0x000F的数据 以下语句与上面的语句等效: #define EX_RAM XBYTE[0x000F] //将EX_RAM定义为外部RAM的地址0x000F EX_RAM=data;// 此语句表示将data写到外部RAM中的0x000F data=EX_RAM // 此语句表示读取外部RAM中0x000F的数据 18、如何在keil中用汇编实现51中没有的指令 部分MCU与8051兼容,但会增加8051中没有的指令,如华邦的W77E58和N79E352等芯片,具有8051中没有的指令DEC DPTR。如何才Keil中实现此指令呢? 方法1: 在需要执行该指令的地方放置相应的机器码 MAIN: MOV DPTR,#02H DB 0A5H;由于从数据手册上得知,DEC DPTR的机器码为0A5H,故此处相当于执行了DEC DPTR指令。 AJMP $ END 方法2: 使用宏定义的方法 /*宏定义,表示用DEC_DPTR代替MACRO与ENDM之间的内容*/ DEC_DPTR MACRO DB 0A5H;此处不能与MACRO同一行 ENDM MAIN: MOV DPTR,#02H DEC_DPTR;放置机器码0A5H,相当于执行DEC DPTR AJMP $ END 通过将以上两种方法生成的hex文件调入到编程器中,发现代码一样。经测试,同样可以用以上两种方法代替8051中已有的指令。 例如,从数据手册可知,MOV A,#0FH的长度为2字节,机器码的值为74H,0FH。因此,经验证,以下三个程序等效,产生的HEX文件一样 MAIN: MOV A,#55H DB 74H DB 0FH MOV P1,A AJMP $ END MAIN: MOV A,#55H MOV A,#0FH MOV P1,A AJMP $ END TEST MACRO DB 74H DB 0FH ENDM MAIN: MOV A,#55H TEST MOV P1,A AJMP $ END 18、汇编中包含头步骤: 例如,T2CON为定时器2的特殊功能寄存器,地址为0C8H,要对此寄存器赋值01H,除了 MOV 0C8H,#01H 和 T2CON EQU 0C8H MOV T2CON,#01H 外,还有用包含头文件的方法 #include 19、指针 C51 提供一个3 字节的通用存储器指针。通用指针的头一个字节表明指针所指的存储 区空间,另外两个字节存储16 位偏移量。对于DATA IDATA 和PDATA 段只需要8 位偏移量。Keil 允许使用者规定指针指向的存储段,这种指针叫具体指针。使用具体指针的好处是节省了存储空间编译器不用为存储器选择和决定正确的存储器操作指令产生代码这样就使代码更加简短但你必须保证指针不指向你所声明的存储区以外的地方否则会产生错误而且很难调试。 由于使用具体指针能够节省不少时间所以我们一般都不使用通用指针。 20、EEPROM存放开关机(复位)次数方法:每次开机(复位)读取EEPROM存放开关机的数据,并加1后重新写入EEPROM。 21、C51中,将printf函数与串口输出结合注意事项: a、关串口中断; b、初始化串口,并使TI=1; c、KEIL里扩展出了b(8位),h(16位),l(32位)来对输入字节宽的设置 在Keil C51中用printf输出一个单字节变量时要使用%bd,若使用%d,则默认为双字节宽度,输出可能会出错。如 unsigned char counter;printf(“Current count: %bdn”, counter);而在标准C语言中都是使用%d: printf(“Current count: %dn”, counter);d、输出数据类型的长度应与定义的数据类型长度一致,如: uint tem2=97; printf(“%c,%bdn”,tem2,tem2);第一个输出会出错。 22、我一般不刻意的注意这个,都是从软件自身找问题的。 我写程序时对于软件抗干扰都是在程序状态上考虑意外情况的,例如: if(a == 1){...} else if(a == 2){....} else{//这个else 一定得加的,即使自己认为不可能出现的情况也要加上 ..//经过好多程序走飞的情况发现:大多情况都是缺少这个语句条件的,这 //语句可以写成重新初始化a } 还有程序出现堆栈比较深的运算(例如浮点乘除法后)或中断比较深,我加2个_nop_(); 23、STC12C5410AD外部RAM使用方法: a.在Keil中设置外部RAM的起始地址和大小,如下图 b.将变量定义为xdata即可。 24、中断嵌套 当有外部中断0时,中断标志位IE0由硬件自动置1,进入中断服务程序后,IE0被自动清0。若外部中断0触发信号在执行完中断服务程序后仍没有撤除,就会再次使已经变0的中断标志位IE0置1,再次进入中断服务程序;若在响应中断服务程序期间,再次产生外部中断0触发信号时,此中断不能被识别,因为CPU在响应中断时会自动关闭同一中断。 如果外部中断0比外部中断1的优先级高,当在响应外部中断0期间产生外部中断1时,如果执行完外部中断0后,外部中断1的中断请求标志位IE1仍没有清除的话,将会响应外部中断1的请求;但是如果在响应外部中断0期间,外部中断1的触发信号产生后又撤除的话,IE1也会自动清除,也就是说,执行完外部中断0后,不会去响应外部中断1。 当多个中断源同时向CPU请求中断时,CPU就可以通过中断优先权电路率先响应中断优先权高的中断请求,而把中断优先权低的中断请求暂时搁置起来,等到处理完优先权高的中断请求后再来响应优先权低的中断。 如果某一中断源提出中断请求后,CPU不能立即响应,只要该中断请求标志位不被软件人为清除,中断请求的状态就将一直保持,直到CPU响应中断为止。但是对于串行口中断,即使CPU响应了中断,其中断标志位RI/TI也不会自动清零,而必须在中断服务程序中设置 清除RI/TI的指令后,才会再一次地提出中断请求。 25、在满足应用要求的前提下,选择配较低的单片机,较小的RAM/ROM、较低的ADC分辨率、较低的ADC速率,较少的IO管脚都可以降低单片机的整体功耗。当然了,这个得能满足你产品需求的前提下。 26、对于一个数字系统而言,其功耗大致满足公式:P=CV2f。其中C为系统的负载电容,V为电源电压,f为系统工作频率[2]。功耗与电源电压的平方成正比,因此电源电压对系统的功耗影响最大,其次是工作频率,再次就是负载电容。负载电容对设计人员而言,一般是不可控的,因此设计一个低功耗系统,在不影响系统性能的前提下,尽可能地降低电源的电压和工作频率。对于大多数低功耗单片机来说,工作频率越低,意味着消耗的电流也越小,但是不能认为频率越低,系统整体功耗越小,因为工作频率降低,意味着需要更长的处理时间,其他外围电路消耗的电能就越多。目前有很多单片机都允许有两个或者两个以上的时钟源,低频时钟作为如UART、定时器等外围功能器件的时钟源,高频时钟作为系统的主时钟。在不需要高速运行的场合下,低频时钟也可以作为系统主时钟使用。对于需要在工作状态与空闲状态之间频繁切换的应用,在考虑单片机本身低功耗的同时,应该考虑切换时间和切换电流。考虑到有些场合单片机的工作特点,选择单片机不光要关注工作电流,更应该关注单片机休眠时的静态电流。单片机丰富的低功耗模式和极低的静态电流,在满足特定应用功能的同时,有效降低系统的功耗。尽量关闭MCU内部不用的资源,比如ATmega8内部的模拟比较器,默认是开着的,还有ATmega88内部的大多数资源都可以在不用的时候用软件关闭。 27、定时/ 计数器的实时性 定时/ 计数器启动计数后,当计满回0 溢出向主机请求中断处理,由内部硬件自动进行。但从回0 溢出请求中断到主机响应中断并作出处理存在时间延迟,且这种延时随中断请求时的现场环境的不同而不同,一般需延时3 个机器周期以上,这就给实时处理带来误差差。大多数应用场合可忽略不计,但对某些要求实时性苛刻的场合,可采用动态补偿措施。 所谓动态补偿,即在中断服务程序中对THx、TLx 重新置计数初值时,应将THx、TLx 从回0 溢出又重新从0 开始继续计数的值读出,并补偿到原计数初值中去进行重新设置。可考虑如下补偿方法: CLR EA ;禁止中断 MOV A,T L x ;读TLx 中已计数值 ADD A,#LOW ;LOW 为原低字节计数初值 MOV T L x,A ;设置低字节计数初值 MOV A,#HIGH ;原高字节计数初值送A ADDC A,T H x ;高字节计数初值补偿 MOV T H x,A ;置高字节计数初值 SETB EA ;开中断 28、动态读取运行中的定时器/计数值 在动态读取运行中的定时/ 计数器的计数值时,如果不加注意,就可能出错。这是因为不可能在同一时刻同时读取THx 和TLx 中的计数值。比如,先读TLx 后读THx,因为定时/ 计数器处于运行状态,在读TLx 时尚未产生向THx 进位,而在读THx 前已产生进位,这时读得的THx 就不对了;同样,先读THx 后读TLx 也可能出错。 一种可避免读错的方法是:先读THx,后读TLx,将两次读得的THx 进行比较;若两次读得的值相等,则可确定读的值是正确的,否则重复上述过程,重复读得的值一般不会再错。此法的软件编程如下: RDTM: MOV A,THx ;读取THx 存A 中 MOV R0,TLx ; 读取TLx 存R0 中 CJNE A,THx,RDTM ;比较两次THx 值,若相等,则读得的值正确,否则重读 MOV R1,A ;将THx 存于R1 中 29、掉电及空闲模式 掉电方式 当PCON中的第二位PD为1时,进入掉电模式,不会执行任何指令,外部时钟停振,片内所有功能部件停止工作,如定时器,串行口,外部中断(部分增强型8051的外部中断可以工作),但片内RAM和SFR的内容保持不变。标准8051从掉电状态退出的惟一方法是硬件复位(部分增强型8051还可以通过外部中断来退出掉电状态),复位后,SFR被重新初始化,但RAM的内容不变。因此,若要使得8051在供电恢复正常后继续执行掉电前的程序,那就必须在掉电前预先把SFR中的内容保护到片内RAM,并在供电恢复正常后为SFR恢复到掉电前的状态。 当PCON的第一位IDEL为1时,进入空闲模式,CPU停止工作,不会执行任何指令,但中断、串行口和定时器可以继续工作。此时,CPU现场(即SP、PC、PSW和ACC等)、片内RAM和SFR中其他寄存器内容均维持不变。退出空闲模式有两种方法: 一、被允许中断的中断源发出中断请求; 二、硬件复位。30、看门狗应用 将喂狗操作(取反指令,如 CPL P1.0)分成两步,放在主程序和中断里执行。如将SETB P1.0放在主程序中,将CLR P1.0放在中断里,这样可以避免主程序跑飞,中断功能正常或者主程序正常,而中断跑飞的情况导致看门狗失效。 31、volatile作用 如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。 一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义; 另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。32、51准双向口读取: 只有1条指令: MOV A,P1为读端口寄存器 有两条指令: MOV A,#0FFH MOV A,P1为读引脚 33、采用C语言和汇编语言混合编程是最佳的选择; 34、系统投入运行的最初时刻,应对系统进行自检和初始化。开机自检在初始化前执行,如果自检无误,则对系统进行正常初始化,通常包括硬件初始化和软件初始化两个部分。硬件初始化是指对系统中的各种硬件资源设定明确的初始状态,如对各种可编程芯片进行编程、对各I/O端口设定初始状态和为单片机的硬件资源分配任务等。软件初始化包括,对中断的安排、对堆栈的安排、状态变量的初始化、各种软件标志的初始化、系统时钟的初始化和各 种变量储存单元的初始化等。 35、按键连击速度一般为3-4次/s。 36、复合键利用两个以上按键同时按下时产生的按键效果,但实际情况下,不可能做到真正的“同时按下”,它们的时间差可以长达50ms左右,故当检测到有KEY1按键按下时,还要等待超过50ms,再判断是否还有其他按键按下,再解析按键。 37、数码管显示闪烁效果时,一般闪烁速度为1-4次/s。 38、大电流和高电压设备的启动和关闭都是由软件指令来完成,这些指令执行后,必然引起强烈的干扰,这些干扰不能算随机干扰,它们与软件完全相关;可以在最后才执行这些可能引起强烈干扰的I/O操作,之后立即进入睡眠状态,这样就不会干扰到CPU,等CPU醒来后,干扰的高峰也基本过去。 39、用积分时间为20ms整数倍的双积分型A/D转换方式,能有效地抑制50Hz工频干扰。40、掉电检测电路必须在电压下降到CPU最低工作电压之前就提出中断申请,提前时间为几百us到数ms,以便掉电中断程序进行掉电保护。 41、用定时器作看门狗:当为专职看门狗时,在主程序中周期性清0定时器计数值,以使定时器中断不能产生,当产生定时器中断时,表明看门狗溢出,此时应执行出错处理程序或者进行复位。当为兼职看门狗时,可以在定时器中断程序对计数值进行加1,若计数值大于某值时,表明看门狗溢出,而主程序中应周期性地对计数值进行清0。 42、中断中,冲突发生的条件: 1)某一资源为中断程序和主程序所使用;该资源可以为1个变量,也可以为1个数组或者1个缓冲区。 2)中断程序或主程序对该资源进行了写操作; 3)主程序不能用一条指令对资源完成读或者写操作。(这条不对,参考深入浅出AVR单片机P100的例子) 当这三个条件均满足时,即有可能发生资源冲突,导致程序偶然运行不正常。为了避免发生冲突,可以在主程序中先关中断,再对资源进行读或写,结束后再开中断。 当主程序对资源的访问比较费时,长期关中断可能影响系统的实时性;解决的办法是尽可能缩短关中断的时间,将一边访问,一边处理的工作方式改为集中访问,分批处理。如果是读该资源,则关中断迅速将该资源的内容转移到缓冲区,再开中断,然后再对缓冲区中的信息进行处理;如果是写该资源,则先边运算边写缓冲区,全部写好后再关中断,然后迅速将缓冲区中的内容复制到该资源中,边可以开中断了。 43、A/B*C的运算方案不如(A*C)/B的运算方案精度高。因此,应尽可能将出现偏差的运算往后排,先进行无偏差或偏差小的运算。在定点运算系统中,加减法只要不超限,是没有偏差的,乘法运算的结果会使字长增加,如双字节乘双字节,积为四字节,如果保留全部结果,则没有偏差的。乘法运算的结果会使字长增加,如双字节乘双字节,积为四字节,如果保留全部结果,则没有偏差;如果受字长限制,则要舍去低位字节,从而产生舍入偏差。除法几乎都是有偏差的能够刚好整除的情况是很少的。在浮点运算系统中,加减法由于要进行对阶操作,当两操作数的阶码相差较大时,绝对值大的数有可能将绝对值小的数淹没,使运算的结果仍为绝对值大的数,一点儿也看不出绝对值小的数对结果的影响。相比之下,浮点乘法和浮点除法引起的偏差就比较小,它们能够保持一个比较稳定的运算精度。另外,不管在定点系统中还是在浮点系统中,都要尽可能避免两个数值相近的数过早相减,因为他们都可能是近似值,相减以后,差的有效数值大大减少,必然带来更大的相对误差。经过后续运算之后,结果可能离真实值相差甚远。再有,尽可能不要用绝对值小的数作分母,否则引起的误差也是很大的。 44、要对软件标志位的使用进行说明;对于全局定义的软件标志,它有惟一的定义;对于局 部定义的软件标志,必须注明其有效范围。 45、软件理论已经证明:任何一个程序(除某些短小的子程序外)都存在错误(缺陷),人们可以通过合理的测试来证明它仍然存在错误,却无法证明它已经没有错误。软件测试应该把发现错误作为目的,而不能把“程序调通”作为目的。 1.P0口能驱动8个TTL电路意思: 8051单片机P0口驱动8个TTL电路的意思,TTL电路输入悬浮时相当于输入高电平,因此P0口输出高电平驱动TTL电路几乎不需输出电流。TTL电路输入为低电平时最少要释放1mA电流,因此P0口输出低电平时吸收的电流大于8mA。TTL输出高电平最大1.6mA,输出低电平时吸收的最大电流 16mA。51输出最好用低电平有效,推动PNP管,因为51复位后IO为高电平,如果用高电平有效推N管的话上电复位后会先让外部电路动做。 2.在51里,有一条指令没有写进书本,机器码为A5,执行操作:将下一个字节跳过而不管它是单字节指令还是双字节或三字节指令的一部分.如果反汇编工具不识别A5指令的话,你在A5以后的程序反汇编后就错乱无章.当成个数据,用db a5 即可 3.有些51系统容易复位,一般是电路设计上的问题。很多电路介绍的复位电路都是10u和8.2k,但是在实践过程中我们发现该电路在电源不稳时很容易复位,特别是附近有大干扰时,如继电器动作等。我建议使用22u和1k的复位电路,有许多电路改为该数值后就工作稳定了。当然,最好的办法还是使用专用复位电路或三极管电路,但是那样要增加成本和体积。 4.电路中的滤波电容一定要注意加上,最好每个芯片都再加一个约0.1uf的电容,这样对电路的稳定性很有好处。如果使用了看门狗电路,就有可能是软件问题,程序工作到某些环节时忘记了复位看门狗,结果计数满了就复位了。 5.如果在中断程序中改变了多字节类型的变量,那么中断程序以外的程序中(主程序,子函数),读写前要关中断,读写后再开中断。举一反三: 其他的数据类型也可能有这种影响。例如:长整型、浮点型。 上面的例子是中断里写,主程序中读。相反主程序写,中断里读也可能出错。 6.教你一招,别说我损。。 写一个测试代码,反复向EEPROM中的某几个不用的空位字节写入0x55,直到把它干到寿命终结不能写为止,如果按照10MS写一个字节计算的话,大约只需要20分钟就能干掉它。然后向这个芯片中烧入你的正常代码,当然了,这个代码中应该有一段上电检测EEPROM这几个字节的代码,先尝试向它写入0Xaa,然后再读出来看看是否写入成功,如果没写入则再来两次,如果始终不能写入,这当作检查通过,如果就判断为检查失败,这个时候代码要装着‘不知情’继续执行正确代码,下面的‘破坏’行为应该如何做就不要我讲了把? 破坏行为要装的掩蔽一点,例如调一段代码檫除FLASH的代码,嘿嘿,那对方肯定以为CHIP质量不好容易出现FLASH数据丢失,如果对方使用了AD什么的,可以偶尔人为让它波动大一点,这样对方一般只会怀疑PCB和硬件电路弄的不好,而不会想到是代码动手脚了,长久以后他的用户肯定也会认为他们的产品质量不好,你这个时候就可以向他的客户推广你的产品了。。 上电写EEPROM的次数要在你自己的产品质量承诺的寿命时间之内,否则你自己的产品也 可能增加维修。。 这个方法特别适合在外接单挣钱的工程师,你可能给了对方几个CHIP做测试,对方测试通过偏说不行,就是不给你余款,然后把CHIP拿去CRACK,妄想省掉这个钱,NND,让他们见鬼去把,俺这招已经对付了不少不良分子。。 7.AD键盘 8.防解密高招 高招, 解密 使用一些带内部晶振和内部EEPROM的单片机,如PIC16F913和ATMEGA8等,带内部晶振的单片机有一个寄存器OSCTUNE(或OSCCAL),这个是芯片厂家用来校准内部晶振的,范围从0-31,出厂时同型号的单片机这个寄存器的值是不一样.我们可以利用一些隐藏功能,将OSCTUNE寄存器的值存入内部的EEPROM中,开机时读取EEPROM的值,再与OSCTUNE的值相比较, 若二者相同系统正常工作,若不 相同则不正常工作.解密者将解密的程序烧写进单片机中后,会发大部分的芯片不能正常工作,因为他们不知道这个隐藏的功能.举例说明: 芯片为PIC16F913,这个厂品有4个按键(KEY0、KEY1、KEY2、KEY3),内部我们可以设定这样子一个隐藏的功能,如果KEY0与KEY1同时按下3秒钟以上,会将OSCTUNE寄存器存入单片机的EEPROM中。 开机复位后,读取EEPROM中的数据,与OSCTUNE寄存器相比较,若二者相同系统正常工作,若不相同则不正常工作。以上有三个重点: 1、对于OSCTUNE寄存器不要进行写的操作,只进行读的操作,因为写了一次以后,就一直是你写的这个数据的。 2、刚才介绍的KEY0、KEY1同时按下3秒钟这个功能,可不能让解密者(包括产品的用户)知道,当然大家可以用别的隐藏的功能。 3、单片机中的OSCTUNE寄存器(或OSCCAL)的值,同一种型号的单片机不是每一个都是一样的,有32个数据,也就是说32个芯片中有一个是与解密的单片机是一样的。这样子造成的后果是:解密者解密了你的程序以后,却发现有些单片机可以正常工作,可有些单片机不能正常工作,可以说是大部分的单片机不能正常工作。 不过需要注意一下:要是遇到强干扰把EEPROM中的数据改变了看客户怎么收拾你! 9.PIC16F887A中,要求SLEEP指令后的下一条指令为NOP;不知51和AVR的芯片是否需要注意这一点。经查,AVR的datasheet无此要求,可能是其唤醒时,存在启动延时。 10.中断随时随刻都有可能产生,故编写程序时,需要时刻注意中断的影响。 11.注意以下语句在某些编译器下,结果可能出错: unsigned char a,b; unsigned int sum; a=0x80; b=0x80; sum=a+b; 12.编程序最重要是好维护。几个执行时间和程序的可读性比,和开发时间比,我认为是不用考虑的。为了几个机器周期而把程序搞得很复杂,是非常愚蠢的行为。可是很多人多乐此不疲啊。总体系统的算法是要考虑优化的问题的,这点我是赞同的。天天在技术上对着几行程序去优化,而导致开发速度减慢,是非常愚蠢的行为。 13.串口通信协议:引导码/识别码+长度+命令字+data+校验 通过引导码/识别码、长度、校验三步检测 每当出错则丢弃当前数据并还原接收状态和空间………… 14.当准备调试一块板的时候,一定要先认真的做好目视检查,检查在焊接的过程中是否有可见的短路和管脚搭锡等故障,检查是否有元器件型号放置错误,第 一脚放置错误,漏装配等问题,然后用万用表测量各个电源到地的电阻,以检查是否有短路,这个好习惯可以避免贸然上电后损坏单板。调试的过程中要有平和的心态,遇见问题是非常正常的,要做的就是多做比较和分析,逐步的排除可能的原因,要坚信“凡事都是有办法解决的”和“问题出现一定有它的原因”,这样最后一定能调试成功。 做一个硬件设计人员要锻炼出良好的沟通能力,面对压力的调节能力,同一时间处理多个事务的协调和决断能力和良好平和的心态,还有细心和认真等等。 void main() { int driver,mode; driver=DETECT; mode=0; initgraph(&driver,&mode,“"); setcolor(15); line(66,66,88,88); lineto(100,100); linerel(36,64); getch(); restorecrtmode(); } -------------- #include #include void circlePoint(int x,int y)/*八分法画圆程序*/ { circle(320 x*20,240 y*20,3); circle(320 y*20,240 x*20,3); circle(320-y*20,240 x*20,3); circle(320-x*20,240 y*20,3); circle(320-x*20,240 y*20,3); circle(320-x*20,240-y*20,3); circle(320-y*20,240-x*20,3); circle(320 y*20,240-x*20,3); circle(320 x*20,240-y*20,3); } void MidBresenhamcircle(int r)/* 中点Bresenham算法画圆的程序 */ { int x,y,d; x=0;y=r;d=1-r;/* 计算初始值 */ while(x { circlePoint(x,y);/* 绘制点(x,y)及其在八分圆中的另外7个对称点 */ if(d<0)d =2*x 3;/* 根据误差项d的判断,决定非最大位移方向上是走还是不走 */ else { d =2*(x-y)5; y--; } x; delay(900000); } /* while */ } main() { int i,j,r,graphmode,graphdriver; detectgraph(&graphdriver,&graphmode); initgraph(&graphdriver,&graphmode,” “); printf(”中点Bresenhamcircle算法画圆的程序n“);/*提示信息*/ printf(”注意 |r|<=11“); printf(”n输入半径值 r:“); scanf(”%d“,&r); printf(”按任意键显示图形...“); getch(); cleardevice(); setbkcolor(BLACK); for(i=20;i<=620;i =20)/*使用双循环画点函数画出表格中的纵坐标*/ for(j=20;j<=460;j) putpixel(i,j,2); for(j=20;j<=460;j =20)/*使用双循环画点函数画出表格中的横坐标*/ for(i=20;i<=620;i) putpixel(i,j,2); outtextxy(320,245,”0“);/*原点坐标*/ outtextxy(320-5*20,245,”-5“);circle(320-5*20,240,2);/*横坐标值*/ outtextxy(320 5*20,245,”5“);circle(320 5*20,240,2); outtextxy(320-10*20,245,”-10“);circle(320-10*20,240,2); outtextxy(320 10*20,245,”10“);circle(320 10*20,240,2); outtextxy(320-15*20,245,”-15“);circle(320-15*20,240,2); outtextxy(320 15*20,245,”15“);circle(320 15*20,240,2); outtextxy(320,240-5*20,”-5“);circle(320,240-5*20,2);/*纵坐标值*/ outtextxy(320,240 5*20,”5“);circle(320,240 5*20,2); outtextxy(320,240-10*20,”-10“);circle(320,240-10*20,2); outtextxy(320,240 10*20,”10“);circle(320,240 10*20,2); outtextxy(20,10,”The center of the circle is(0,0)“);/*坐标轴左上角显示提示信息*/ setcolor(RED);/*标记坐标轴*/ line(20,240,620,240);outtextxy(320 15*20,230,”X“); line(320,20,320,460);outtextxy(330,20,”Y“); setcolor(YELLOW); MidBresenhamcircle(r); setcolor(BLUE);/*绘制圆*/ circle(320,240,r*20); setcolor(2); getch(); closegraph(); } -------------------------#include void main() { int driver,mode; driver=DETECT; mode=0; initgraph(&driver,&mode,”"); setcolor(15); circle(20,20,20); getch(); 结构化查询语言 (Structured Query Language, SQL) 是最普遍使用的关系数据库语言, 它具有表达能力强, 功能丰富, 语言简洁, 使用灵活等特点, 在许多数据库系统环境中, 它作为独立语言由用户在交互环境下使用。 由于SQL语言是一种面向集合运算的描述性语言, 本身不具有过程性结构, 而许多实际事物处理应用都是过程性的, 需要根据不同的条件来执行不同的任务, 因此单纯用SQL语言在交互式环境中执行很难满足应用的需求。为了解决这一问题, 将SQL语言嵌入到某种高级语言中使用, 利用高级语言的过程性结构来弥补SQL语言实现复杂应用方面的不足, 相辅相成, 发挥各自优势。这种方式下使用的SQL语言称为嵌入式SQL, 而嵌入SQL的高级语言称为主语言或宿主语言。 (二) 基于C语言和SQL Server2000的嵌入式SQL的形式 对于嵌入式SQL语句, 数据库管理系统可采用两种方法处理:一种是预编译方法;另一种是修改和扩充主语言使其能识别处理SQL语句。本文采用的是SQL Server2000预编译方法, 由DBMS的预编译器 (NSQLPREP文件) 扫描识别处理源程序中的SQL语句, 把SQL语句转换成主语言 (C语言) 调用语句, 以使主语言编译程序 (这里采用VC++编译程序) 能识别它并将整个源程序编译成目标代码, 连接后形成可执行文件。 为了在嵌入式SQL中区别SQL语句与主语言语句, 须在所有的SQL语句前加前缀EXEC SQL, 而SQL语句的结束标志随宿主语言的不同而不同, C语言中以分号结束, 一般形式为“EXEC SQL 嵌入式SQL语句分为可执行语句和说明性语句, 可执行语句可出现在主语言中任何允许高级语言的执行语句出现的地方, 它完成在交互式环境下的SQL语句能完成的任务, 包括数据定义、数据控制和数据操纵三种语句。说明性语句用于声明通信区和SQL变量等。位于主语言中任何允许出现说明性的语句的地方。 (三) 嵌入式SQL语句与C宿主语言之间的通信 C语言是一种过程性的、与运行环境有关的语言, SQL语言是面向集合的描述性、非过程性语言, 将两者混合编程, 目的在于发挥各自的优势, SQL语句负责操纵SQL Server2000数据库, C语言负责控制程序流程。程序执行过程中, 两者之间需要进行通信, 过程如下:SQL语句将执行状态信息传给C语言;C语言给SQL语句提供一些变量参数;将SQL语句查询结果返回给C语言做进一步处理。 1. SQL通信区 SQL Server数据库管理系统提供了一个通信区SQLCA, 作为SQL Server2000和应用程序的一个接口, 该结构变量是为诊断错误和事件处理而设置的。SQL语句执行后, 系统将当前工作状态和运行环境的各种参数送到通信区SQLCA中, 主语言的应用程序从SQLCA中取出这些状态信息以决定其语句的执行。在C语言中定义SQL通信区的语句为: EXEC SQL INCLUDE SQLCA; 2. 变量的说明与引用 嵌入式SQL中有两种变量:主变量和指示变量。SQL语句中使用的主语言程序定义的变量称为主变量, 主要完成嵌入式SQL语句的数据输入与输出。指示变量是与主语言相关联的一类SQL变量, 被用于监督和管理与其相关联的主变量。每个主变量都可以定义一个指示器变量。指示其变量的具体作用是:向数据库表列输入NULL值, 检查从数据库表列中选取的数据是否是NULL值或者是否发生截断问题。 SQL变量在引用之前要先说明, 在说明段内使用C语言的类型说明语句为每个SQL变量指定一个SQL Server能支持的C数据类型。如: 在SQL语句中使用SQL变量时, 必须在其之前加一个冒号以与字段名相区别, 但是在C语句中引用时, 不需加冒号。指示器变量引用时必须附在其相关联的主变量之后。例如: 3. 连接SQL Server数据库 C程序的主函数中应包含一条登录语句, 向预编译程序提供用户名和口令, 以与SQL Server数据库管理系统建立连接, 其命令语法为: EXEC SQL CONNECT TO服务器名.数据库名AS连接名USER用户名.口令 (四) 程序结构 嵌入式SQL语句在C语言中的编程结构一般分为以下四步: 1. 定义通信区域。 2. 定义主变量。 3. 连接所要访问的数据库。 4. 访问数据库。 (五) 实例说明 1. 软件安装及环境设置 安装SQL Server2000时, 使用客户自定义模式, 选中“头文件和库文件、MAC、SDK、备份/还原API和调试程序界面”进行安装。 在VC++6.0中新建名为STU的WIN32 Console Application工程文件。在“工具”菜单项下选择“选择”, 再选择“目录”以设置工作区的的运行环境。 (1) 在“S显示目录为”下拉框中选择“Include files”, 在路径编辑框中输入SQL Server开发工具的头文件路径“C:PROGRAM FILESMICROSOFT SQL SERVER80TOOLSDEVTOOLSINCLUDE”;同理, 新增“Library files”的路径“C:PROGRAM FILESMICROSOFT SQL SERVER80TOOLSDEVTOOLSLIB”和“Executable files”的路径“C:PROGRAMFILESMICROSOFT SQL SERVERMSSQLBINN”。 (2) 在STU工程的源文件目录下创建并添加文件student.sqc, 编写嵌入式SQL的C源程序, 程序部分代码见 (5) 。 (3) 在student.sqc文件上单击右键, 选择settings, 在命令编辑框中输入“NSQLPREP student.sqc”, 在输出编辑框中输入“student.c”。编译student.sqc, 将其预编译成student.c。再将student.c加到源文件目录下, 将其编译成目标文件。 (4) 单击“工程”菜单项下的“设置”命令, 在link页下的object/library modules中加入“caw32.lib和sqlakw32.lib”两个库, 并将“MICROSOFT SQL SERVERMSSQLBINN”下的sqlakw.32.dll复制到当前目录或工程目录中, 并保证windows的system目录下有Ntwdblib.dll和Dbnmpntw.dll, 则可连接成功。 2. 数据库表结构 本文设计了一个包含数据插入、删除、更新和查询的例子。在SQL Server2000 DBMS中设计了一个学生信息数据库student, 用户名和密码均为“ww”, 其中的学生基本信息表S的结构如图1所示。 3. 程序模块结构 该C程序主要由一个MAIN函数及四个子函数构成, 通过对四个子函数的调用来完成对学生基本信息表的操作, 其模块结构如图2所示。 4. 部分程序清单 (1) 主程序模块 (2) 插入模块 摘要:文章旨在研究用嵌入式SQL语言开发SQL Server数据库应用的方法。首先介绍了C语言与SQL Server2000的嵌入式SQL的形式, 然后给出嵌入式SQL语句与C宿主语言之间的通信方式及程序结构, 最后给出了代码实例。 关键词:嵌入式SQL,宿主语言,SQL Server2000数据库 参考文献 [1]陶宏才.数据库原理及设计[M].北京:清华大学出版社, 2004, 2. [2]丁宝康, 董健全.数据库实用教程[M].北京:清华大学出版社, 2001, 9. 关键词:C语言;C语言编程;教学 中图分类号:G642 文献标识码:A文章编号:1007-9599 (2011) 09-0000-01 C Language Programming Teaching Method Wang Tiaoshan (Huizhou Agricultural School,Huizhou516023,China) Abstract:With advances in computer development,C language by the majority of computer workers attention and recognition.To this end,the national colleges and universities have set up a C language program.Introduction to C programming language,but easy,however,to enable students to fully grasp the programming skills,it makes the process of teaching is very difficult,following the author's teaching on the C language problems and solutions in more detail. Keywords:C language;C language programming;Teaching 一、前言 21世纪,人们自然对未来有许多美好的愿望和设想。现代科学技术的飞速发展,改变了世界,也改变了人们的生活。作为新世纪的大学生,应当站在时代发展的前列,掌握现代科学技术知识,完善自己的知识结构和能力结构,以适应社会的发展要求。新世纪需要具有丰富的现代科学知识,能够独立解决面临的任务,充满活力,有创新意识的新型人才。 掌握计算机知识和应用无疑是培养新型人才的一个重要环节。计算机既是现代科学技术的结晶,又是大众化的工具。学习计算机知识不仅是为了掌握一种技能,更重要的是:它能启发人们对先进科学的向往,启发创新意识,推动新知识的学习,培养自学能力,锻炼动手实践的本领。因此,C语言教学就成为高等学校素质教育中极为重要的一部分。 二、C语言教学过程中出现的问题 (一)教学大众化,缺乏层次教学能力。在C语言的教学过程中,老师和学生的互动很少,老师只是一味的完成自己课前预定的教学任务,达不到针对不同层次水平的学生完成教学的目的。而学生在课堂上由于学习水平分级较大,会造成两极分化的严重性,会者不听,不会者难以理解的问题。 (二)老师缺乏情感投入,学生烦躁厌学。在C语言教学管理上,离不开教育者得感情投入。而在现阶段看来,很多老师在这方面做的还不够,错误的认为学生在课堂上可以做到自我管理,所以在教学技巧和方法上就缺乏情趣性,使得学生在学习过程中产生厌学的情绪,不利于进一步深入的学习。 (三)忽视了课堂上学生问题的存在。如果课堂上存在问题,不仅会影响课堂教育管理和其他学生学习的正常进行,严重的更会对学生的成长不利。其实课堂教育管理者要重视这一问题,必须调控课堂学习有效的进展,要坚决杜绝老师在课堂上对出现的问题忽视不见的情况发生。 (四)学生在学习C语言时出现的误区。随着C语言编程教学过程的不断深入,需要联想思考和记忆的相关内容难度会逐渐增大,这样就使得学生有时会陷入没有意义的算法中,这种只见树木不见森林的感觉,会使学生在学习过程中渐渐失去兴趣,调动不起学习的积极性,觉得学习C语言的学习是非常枯燥的。就算是在上机练习练习的时候也感到索然误区,一直照着课本上的例题,从头到尾输入计算机,得出与书上结果一致的答案就算上机通过,并没有真正的掌握语句的真正意义。就算有些学习认真的学生能够掌握课本上的内容,但是一旦要自己独立完成编程题的时候却无从下手。这样的结果就导致了学生在学习C语言编程课程的时候,无法做到知识的融会贯通和举一反三,就不能形成一个全面的C语言编程的知识体系。这对C语言编程教学的初衷是相违背的。 三、C语言编程教学方法 (一)创建以学生为本的多层次互动课堂管理模式。针对学习水平不同的学生,进行不同难度的作业分布,并且老师和同学不僅在课堂上及时交流,还要在课下沟通交流学习方法和技巧。完善C语言上机实践课程,通过增强学生的动手能力,促进其对课本知识的掌握和理论的实际运用。 (二)提高老师教学质量和素质水平。老师作为课堂管理模式的核心,其本身的教学质量和素质水平对于课堂的管理策略有着决定性的影响,正确的认识能促进学生在学习中的积极性,而错误的认识则会对学生的积极心起到负面影响。此外,在课堂管理中老师也要过多的投入感情因素,进而促进和谐课堂的建立,和学生的感情到达共鸣,做到以德服人,以理育人。 (三)改善课堂管理氛围。课堂管理的质量水平主要体现在教学目标与学生发展相符合。要达成既定的课堂管理的目标,就必须创造一种课堂新环境,焕发课堂生机与活力。建立秩序良好的课堂管理模式,首先保证课堂实体环境的舒适程度。其次,建立良好的师生人际交往关系,良好的人际关系能拉近师生关系,推动课堂和谐管理。也为学生减轻心理压力构建心灵的桥梁,是学生积极开朗,乐于好学。 (四)保证教学内容的新颖。根据新世纪的需要,要确保教学内容的新颖,以符合计算机科学技术的发展和C语言教学改革的要求。不仅要保留C语言教材中,通过实践考验,受到广泛认可的优秀教材。还要积极探索今年来迅速得到推广应用的计算机新技术,不断更新补充新的教学内容。 (五)采用多样化的形式。除了文字教学的基本形式外,还有配有习题解答和上机指导。并充分利用现代化教学方式,采用制作的电子出版物进行课堂教学,课下有利学生自学。 四、总结 如果要让学生能上好C语言编程,教育者就必须在教学的过程中摈弃传统的教学方法,既要让学生在学习过程中掌握概念,又要动手编程,还有进行上机的调试运行,衡量课程的好坏,不是看你知不知道,而是会不会干,考核的方法也不能用判断题和选择题,而应该把重点放在编制程序和调试程序上。在充分的发挥教师在教学过程的主导作用前提下,调动起学生的学习积极性、主动性和创造性,强烈激发学习兴趣,正确引导学生独立思考,融会贯通地掌握系统的C语言编程知识,使学生主动地学习知识,满足他们的求知欲望,教学管理真只有做到这样,才能取得良好的教学效果。 参考文献: [1]谭浩强.C程序设计(第二版)[M].北京:清华大学出版社,2004 [2]刘昕.论启发式教学[EB/OL].2007,5:13 http://smxx2.zjhyedu.cn/ty/ShowArticle.asp. 【C语言与语言混合编程DSP设计】推荐阅读: dsp的c语言编程10-13 c语言编程经典例题08-30 C语言课程设计与评价学习总结09-12 嵌入式系统c语言编程该怎么学?08-12 c语言课程设计题目09-25 c语言课程设计设计报告10-29 991“数据结构与C语言程序设计”考试大纲(2018版)08-04 c语言程序设计实例06-19 C语言socket课程设计报告11-05 c语言程序设计试题库07-012.C语言与语言混合编程DSP设计 篇二
3.探析基于C语言的DSP程序设计 篇三
4.C语言经典编程题(推荐) 篇四
5.C语言编程自我总结 篇五
6.C语言编程 “画圆”源程序 篇六
7.C语言与语言混合编程DSP设计 篇七
8.C语言编程教学方法探讨 篇八