C51语言应用编程的若干问题
C51编程规范--很好的规范

单片机C51编程规范1单片机C51编程规范-前言为了提高源程序的质量和可维护性,从而最终提高软件产品生产力,特编写此规范。
2 单片机C51编程规范-范围本标准规定了程序设计人员进行程序设计时必须遵循的规范。
本规范主要针对C51编程语言和kei§编译器而言,包括排版、注释、命名、变量使用、代码可测性、程序效率、质量保证等内容。
3 单片机C51编程规范-总则格式清晰注释简明扼要命名规范易懂函数模块化程序易读易维护功能准确实现代码空间效率和时间效率高适度的可扩展性4 单片机C51编程规范-数据类型定义编程时统一采用下述新类型名的方式定义数据类型。
建立一个datatype.h文件,在该文件中进行如下定义:typedef bit BOO§; // 位变量//typedef unsigned char INT8U; // 无符号8位整型变量//typedef signed char INT8S; // 有符号8位整型变量//typedef unsigned int INT16U; // 无符号16位整型变量//typedef signed int INT16S; // 有符号16位整型变量//typedef unsigned §ong INT32U; // 无符号32位整型变量//typedef signed §ong INT32S; // 有符号32位整型变量//typedef f§oat FP32; // 单精度浮点数(32位长度) //typedef doub§e FP64; // 双精度浮点数(64位长度) //5 单片机C51编程规范-标识符命名5.1 命名基本原则§命名要清晰明了,有明确含义,使用完整单词或约定俗成的缩写。
通常,较短的单词可通过去掉元音字母形成缩写;较长的单词可取单词的头几个字母形成缩写。
即"见名知意"。
C51-keil编译常见错误和警告处理

keil错误C51编译器识别错类型有三种1、致命错误:伪指令控制行有错,访问不存在的原文件或头文件等。
2、语法及语义错误:语法和语义错误都发生在原文件中。
有这类错误时,给出提示但不产生目标文件,错误超过一定数量才终止编译。
3、警告:警告出现并不影响目标文件的产生,但执行时有可能发生问题。
程序员应斟酌处理。
D.1 致命错误C_51 FATAL_ERRORACTION: <当前行为>LINE: <错误所在行>ERROR: <错误信息> terminated或C_51 FA TAL ERRORACTION: <当前行为>FILE: <错误所在文件>ERROR: <错误信息> terminatedC_51 TERMINATED C_51(1) ACTION 的有关信息*PARSING INVOKE-/#PRAGMA_LINE在对#pragma 指明的控制行作此法分析时出错。
*ALLOCATING MEMORY系统分配存储空间时出错。
编译较大程序需要512k空间。
*OPENING INPUT_FILE打开文件时,未找到或打不开源文件/头文件。
*CREATE LIST_FILE/OBJECT_FILE/WORK_FILE不能创建上述文件。
可能磁盘满或文件已存在而且写保护。
*PARSING SOURCE_FILE/ANALYZING DECLARATIONS分析源程序时发现外部引用名太多。
*GENERATING INTERMEDIATE CODE源代码被翻译成内部伪代码,错误可能来源于函数太大而超过内部极限。
*WRITING TO FILE在向文件(work,list,prelist或object file)写时发生错误。
(2)ERROR的有关信息*MEMORY SPACE EXHAUSTED所有可用系统空间耗尽。
至少需要512k 字节空间。
c51单片机c语言常用指令 -回复

c51单片机c语言常用指令-回复C51单片机C语言常用指令C51单片机是一种广泛应用于嵌入式系统的微控制器,其C语言编程常用指令为开发者提供了便利。
本文将逐步回答关于C51单片机C语言常用指令的问题,涵盖了常用的输入输出指令、控制流指令、算术指令和逻辑指令等方面,帮助读者全面了解和掌握这些重要的指令。
一、输入输出指令1. 如何在C51单片机上进行输入操作?答:可以使用P1口进行输入操作,需要将P1口配置为输入模式,并使用P1口的位操作函数来读取具体的引脚输入值。
2. 如何在C51单片机上进行输出操作?答:可以使用P2口进行输出操作,需要将P2口配置为输出模式,并使用P2口的位操作函数来设置具体的引脚输出值。
3. 如何控制C51单片机的LED灯?答:可以使用P0口进行LED灯的控制,通过设置P0口的引脚为高电平或低电平来点亮或关闭LED灯。
二、控制流指令1. 如何使用条件语句控制程序的执行顺序?答:可以使用if-else语句或switch语句来进行条件判断,并根据判断结果执行不同的代码块。
2. 如何使用循环语句进行重复操作?答:可以使用for循环、while循环或do-while循环来实现重复操作,根据循环条件控制代码块的执行次数。
三、算术指令1. 如何进行加法运算?答:可以使用加法运算符"+"来进行加法运算,例如:a = b + c;表示将变量b和c的值相加,然后将结果赋值给变量a。
2. 如何进行减法运算?答:可以使用减法运算符"-"来进行减法运算,例如:a = b - c;表示将变量b减去变量c的值,然后将结果赋值给变量a。
四、逻辑指令1. 如何进行逻辑与运算?答:可以使用逻辑与运算符"&&"来进行逻辑与运算,例如:if(a > 0 && b < 10) {...}表示当变量a大于0且变量b小于10时执行相应的操作。
「keilc语言编程常见错误分析」

1.Warning 280:’i’:unreferencedlocal variable 说明局部变量i 在函数中未作任何的存取操作解决方法消除函数中i 变量的宣告及即定义的参数在程序中并未调用2Warning 206:’Music3’:missing function-prototype 说明Music3( )函数未作宣告或未作外部宣告所以无法给其他函数调用解决方法将叙述void Music3(void)写在程序的最前端作宣告如果是其他文件的函数则要写成extern voidMusic3(void),即作外部宣告3Error:318:can’t open file‘beep.h’说明在编译C:\8051\MANN.C程序过程中由于main.c 用了指令#i nclude “beep.h”,但却找不到所致解决方法编写一个beep.h的包含档并存入到c:\8051 的工作目录中ﻫ4 Error237:’LedOn’:function already has a body ﻫ说明LedOn()函数名称重复定义即有两个以上一样的函数名称ﻫ解决方法修正其中的一个函数名称使得函数名称都是独立的ﻫﻫ5 ***WARNING16:UNCALLED SEGMENT,IGNORED FOR OVERLAYPROCESSSEGMENT: ?PR?_DELAYX1MS?DELAY说明DelayX1ms( )函数未被其它函数调用也会占用程序记忆体空间解决方法去掉DelayX1ms()函数或利用条件编译#if …..#endif,可保留该函数并不编译ﻫ6***WARNING6 :XDATASPACE MEMORY OVERLAPFROM : 0025HTO: 0025H ﻫ说明外部资料ROM的0025H 重复定义地址解决方法外部资料ROM 的定义如下Pdata unsigned char XF R_ADC _at_0x25 其中XFR_ADC 变量的名称为0x25,请检查是否有其它的变量名称也是定义在0x25 处并修正它ﻫ7 WARNING206:’DelayX1ms’:missingfunction-prototypeﻫC:\8051\INPUT.CError 267 :’DelayX1ms ‘:requires ANSI-styleprototypeC:\8051\INPUT.C说明程序中有调用DelayX1ms 函数但该函数没定义即未编写程序内容或函数已定义但未作宣告解决方法编写DelayX1ms的内容编写完后也要作宣告或作外部8宣告可在delay.h 的包含档宣告成外部以便其它函数调用ﻫﻫ***WARNING1:UNRESOLVED EXTERNAL SYMBOLﻫSYMBOL:MUSIC3解决办法:1.是文件没有添加到工程里。
单片机c51汇编语言51单片机汇编语言

单片机c51汇编语言51单片机汇编语言单片机C51汇编语言单片机(C51)是指一种集成电路上只包含一个集中式控制器的微处理器,具有完整的CPU指令集、RAM、ROM、I/O接口等功能。
汇编语言是一种低级语言,是用于编写单片机指令的一种语言。
汇编语言能够直接操作单片机的寄存器和输入/输出端口,因此在嵌入式系统的开发中非常重要。
本文将介绍单片机C51的汇编语言编程。
一、了解单片机C51单片机C51是目前应用最广泛的一种单片机系列,广泛用于各种电子设备和嵌入式系统的开发。
C51指的是Intel公司推出的一种基于MCS-51架构的单片机。
该系列单片机具有较高的性能和低功耗的特点,可用于各种控制和通信应用。
二、汇编语言的基本概念汇编语言是一种低级语言,与机器语言紧密相关。
它使用助记符来代替机器指令的二进制表示,使程序的编写更加易读。
在单片机C51汇编语言中,每一条汇编指令都对应着特定的机器指令,可以直接在单片机上执行。
三、汇编语言的基本指令在单片机C51汇编语言中,有一些基本的指令用于控制程序的执行和操作寄存器。
以下是一些常用的指令:1. MOV指令:用于将数据从一个寄存器或内存单元复制到另一个寄存器或内存单元。
2. ADD指令:用于将两个操作数相加,并将结果存储到目的寄存器中。
3. SUB指令:用于将第一个操作数减去第二个操作数,并将结果存储到目的寄存器中。
4. JMP指令:用于无条件跳转到指定的地址。
5. JZ指令:用于在条件为零时跳转到指定的地址。
6. DJNZ指令:用于将指定寄存器的值减一,并根据结果进行跳转。
四、编写单片机C51汇编程序的步骤编写单片机C51汇编程序需要按照以下步骤进行:1. 确定程序的功能和目标。
2. 分析程序的控制流程和数据流程。
3. 设计算法和数据结构。
4. 编写汇编指令,实现程序的功能。
5. 调试程序,并进行测试。
六、实例演示以下是一个简单的单片机C51汇编程序的示例,用于实现两个数的相加,并将结果输出到LED灯上:org 0H ; 程序的起始地址为0mov a, 05H ; 将05H赋值给累加器mov b, 07H ; 将07H赋值给B寄存器add a, b ; 将A寄存器和B寄存器的值相加mov P1, a ; 将相加结果输出到P1口end ; 程序结束在这个例子中,首先将05H赋值给累加器A,然后将07H赋值给B寄存器,接着使用ADD指令将A和B的值相加,将结果存储到累加器A中,最后将累加器A的值输出到P1口。
Keil C51错误及其警告大全

໕ᐺࡇᇙቧᇦ本章列出了编程中可能遇到的致命错误语法错误和警告信息每节包括一个信息的主要说明和消除错误或警告条件可采取的措施致命错误致命错误立即终止编译这些错误通常是命令行指定的无效选项的结果当编译器不能访问一个特定的源包含文件时也产生致命错误致命错误信息采用下面的格式C51 FATAL-ERROR –ACTION<current action>LINE:<line in which the error is detected>ERROR:<corresponding error message> C51 TERMIANTED.C51 FATAL-ERROR –ACTION<current action>FILE:<file in which the error is detected>ERROR:<corresponding error message> C51 TERMIANTED.下面说明Action和Error中可能的内容ActionsALLOCATING MEMORY编译器不能分配足够的存储区来编译指定的源文件CREATING LIST-FILE / OBJECT-FILE / WORKFILE编译器不能建立列表文件OBJ文件或工作文件这个错误的出现可能是磁盘满或写保护或文件已存在和只读GENERATING INTERMEDIATE CODE源文件包含的一个函数太大不能被编译器编译成虚拟代码尝试把函数分小或重新编译OPENING INPUT-FILE编译器不能发现或打开所选的源或包含文件PARSING INVOKE-/#PRAGMA-LINE当在命令行检测到参数计算或在一个#pragma中检测到参数计算就产生这样的错误PARSING SOURCE-FILE/ANALYZING DECLARATIONS源文件包含太多的外部参考减少源文件访问的外部变量和函数的数目WRITING TO FILE当写入列表文件OBJ文件或工作文件时遇到的错误Errors‘(‘ AFTER CONTROL EXPECTED一些控制参数需要用括号包含一个参数当没有左括号时显示本信息‘)’ AFTER PARAMETER EXPECTED本信息表示包含没有参数的右括号BAD DIGIT IN NUMBER一个控制参数的数字参数包含无效字符只能是十进制数CAN’T CREATE FILE在FILE行定义的文件名不能建立CAN’T HA VE GERERAL CONTROL IN INVOCATION LINE一般控制例如EJECT不能包含在命令行把这些控制用#pragma声明放在源文件中FILE DOES NOT EXIST没有发现定义在FILE行的文件FILE WRITE-ERROR因为磁盘空间不够写到列表预打印工作或目标文件时出错IDENTIFIER EXPECTED当DEFINE控制没有参数时产生本信息DEFINE要求一个参数作为标识符这和C语言的规则相同MEMORY SPACE EXHAUSTED编译器不能分配足够的存储区来编译指定的源文件如果始终出现这个信息应该把源文件分成两个或多个小文件再重新编译MORE THAN100ERRORS IN SOURCE-FILE在编译时检测到的错误超过100个这使编译器终止MORE THAN256SEGMENTS/EXTERNALS在一个源文件中的参考超过256个单个的源文件不能有超过256个函数或外部参考这是INTEL目标模块格式OMF-51的历史的限制包含标量和/或bit声明的函数在OBJ文件中生成两个有时候三个段定义NON-NULL ARGUMENT EXPECTED所选的控制参数需要用括号包含一个参数例如一个文件名或一个数字OUT OF RANGE NUMBER一个控制参数的数字参数超出范围例如OPTIMIZE控制只允许数字0到6值7就将产生本错误信息PARSE STACK OVERFLOW解析堆栈溢出如果源程序包含很复杂的表达式或如果块的嵌套深度超过31级就会出现这个错误PREPROCESSOR LINE TOO LONG32K一个中间扩展长度超过32K字符PREPROCESSOR MACROS TOO NESTED在宏扩展期间预处理器所用的堆栈太大这个信息通常表示一个递归的宏定义但也可表示一个宏嵌套太多RESPECIFIED OR CONFLICTING CONTROL一个命令行参数指定了两次或命令行参数冲突SOURCE MUST COME FROM A DISK-FILE源和包含文件必须存在控制台CON CI或类似的设备不能作为输入文件UNKNOWN CONTROL所选的控制参数不认识语法和语义错误语法和语义错误一般出现在源程序中它们确定实际的编程错误当遇到这些错误时编译器尝试绕过错误继续处理源文件当遇到更多的错误时编译器输出另外的错误信息但是不产生OBJ文件语法和语义错误在列表文件中生成一条信息这些错误信息用下面的格式*** ERROR number IN LINE line OF file:error message这里number错误号line对应源文件或包含文件的行号file产生错误的源或包含文件名error message对错误的叙述说明下表按错误号列出了语法和语义错误错误信息列出了主要说明和可能的原因和改正100跳过不可打印字符0x??在源文件中发现一个非法字符注意不检查注释中的字符101字符串没结束一个字符串没有用双引号终止102字符串太长一个字符串不能超过4096个字符用串联符号\在逻辑上可延长字符串超过4096个字符这个模式的行终止符在词汇分析时是连续的103无效的字符常数一个字符常数的格式无效符号\c是无效的除非c是任何可打印的ASCII字符125声明符太复杂20一个目标的声明可包含最多20个类型修饰符[]*这个错误经常伴随着错误126126类型堆栈下溢类型声明堆栈下溢这个错误通常死错误125的副产品127无效存储类一个目标用一个无效的存储空间标识符声明如果一个目标在一个函数外用存储类auto或register声明就会产生本错误129在标记前缺少本错误通常表示前一行缺少分号当出现本错误时编译器会产生很多错误信息130值超出范围在一个using或interrupt标识符后的数字参数是无效的using标识符要求一个0到3之间的寄存器组号interrupt标识符要求一个0到31之间的中断矢量号131函数参数重复一个函数有相同的参数名在函数声明中参数名必须是唯一的132没在正式的参数列表一个函数的参数声明用了一个名称没在参数名列表中例如char function(v0,v1,v2)char *v0,*v1,*v5;/* ‘v5’没在正式列表中 */{/* … */}134函数的xdata/idata/pdata/data不允许函数通常位于code存储区不能在别的存储区运行函数默认定义为存储类型code135bit的存储类错bit标量的声明可能包含一个static或extern存储类register或alien类是无效的136变量用了voidvoid类型只允许作为一个不存在的返回值或一个函数的空参数列表voidfunc(void)或和一个指针组合void *138Interrupt()不能接受或返回值一个中断函数被定义了一个或多个正式的参数或一个返回值中断函数不能包含调用参数或返回值140位在非法的存储空间bit标量的定义可以包含可选的存储类型data如果没有存储类型则默认为data因为位通常在内部数据存储区当试图对一个bit标量定义别的数据类型时会产生本错误141临近标志语法错误期待别的标志…编译器所见的标志是错误的参考所显示的期待的内容142无效的基地址一个sfr或sbit声明的基地址是错误的有效的基地址范围在0x80到0xFF之间如果用符号基地址^位号声明则基地址必须是8的倍数143无效的绝对位地址sbit声明中的绝对位地址必须在0x80到0xFF之间144基地址^位号无效的位号sbit声明中定义的位号必须在0到7之间145未知的sfr146无效sfr一个绝对位基地址^位号的声明包含一个无效的基地址标识符基地址必须是已经声明的sfr任何别的名称是无效的147目标文件太大单个目标文件不能超过6553564K字节-1149struct/union包含函数成员struct或union不能包含一个函数类型的成员但是指向函数的指针是可以的150struct/union包含一个bit成员一个union不能包含bit类型成员这是8051的结构决定的151struct/union自我关联一个结构不能包含自己152位号超出位域位域声明中指定的位号超过给定基类的位号153命名的位域不能为零命名的位域为零只要未命名的位域允许为零154位域指针指向位域的指针不允许155位域要求char/int位域的基类要求char或int unsigned char和unsigned int类型也行156alien只允许对函数157alien函数带可变参数存储类alien只对外部PL/M-51函数允许符号ch a r*,…在alien函数中是非法的PL/M-51函数通常要求一个固定的参数表158函数包含未命名的参数一个函数的参数列表定义包含一个未命名的抽象类型定义这个符号只允许在函数原型中159void后面带类型函数的原型声明可包含一个空参数列表例如int func(void)在void后不能再有类型定义160void无效void类型只在和指针组合或作为一个函数的不存在的返回值中是合法的161忽视了正式参数在一个函数内一个外部函数的声明用了一个没有类型标识符的参数名列表例如extern yylex(a,b,c);180不能指向一个函数指向一个函数的类型是无效的尝试用指针指向一个函数181操作数不兼容对给定的操作符至少一个操作数类型是无效的例如~float_type183左值不能修改要修改的目标位于code存储区或有const属性因此不能修改184sizeof非法操作数sizeof操作符不能确定一个函数或位域的大小185不同的存储空间一个目标声明的存储空间和前一个同样目标声明的存储空间不同186解除参照无效一个内部编译器问题会产生本信息如果本错误重复出现请和技术支持接洽187不是一个左值所需的参数必须是一个可修改的目标地址188未知目标大小因为没有一个数组的维数或间接通过一个void指针一个目标的大小不能计算189&对bit/sfr非法取地址符’&’不允许对bit目标或特殊函数寄存器sfr190&不是一个左值尝试建立一个指针指向一个未知目标193非法操作类型193对ptr非法add/sub193对bit的非法操作193错误操作数类型当对一个给定的操作符用了非法的操作数类型时产生本错误例如无效的表达式如bit*bit ptr+ptr或ptr*anything这个错误信息包括引起错误的操作符下面的操作对bit类型的操作数是可行的赋值=OR/复合OR||=AND/复合AND&&=XOR/复合XOR^^=bit比较= =!=取反~bit操作数可和别的数据类型在表达式中混用在这种情况类型转换自动执行194*间接指向一个未知大小的目标间接操作符*不能和void指针合用因为指针所指的目标的大小是未知的195*间接非法*操作符不能用到非指针参数196存储空间可能无效转换一个常数到一个指针常数产生一个无效的存储空间例如 char*p=0x91234198sizeof返回零sizeof操作符返回一个零199->’的左边要求struct/union指针->操作符的左边参数必须是一个struct指针或一个union指针200.左边要求struct/union.操作符的左边参数要求必须是struct或union类型201未定义的struct/union给定的struct或union名是未知的202未定义的标识符给定的标识符是未定义的203错误的存储类参考名本错误表示编译器的一个问题如果重复出现请接洽技术支持204未定义的成员给定的一个struct或union成员名是未定义的205不能调用一个中断函数一个中断函数不能象一个正常函数一样调用中断的入口和退出代码是特殊的207参数列表声明为void参数列表声明为void的函数不能从调用者接收参数208太多的实参函数调用包含太多的实参209太少的实参调用函数包含太少的实参210太多的嵌套调用函数的嵌套调用不能超过10级211调用不是对一个函数一个函数的调用项不是对一个函数或函数指针求值212间接调用寄存器的参数不匹配通过一个指针的间接函数调用不包含实际的参数一个例外是当所有的参数可以通过寄存器传递这是由于Cx51所用的传递参数的方法被调用的函数名必须是已知的因为参数写到被调用函数的数据段但是对间接调用来说被调用函数的名称是未知的213赋值符的左边不是一个左值赋值符的左边要求一个可修改目标的地址214非法指针转换bit float或集合类型的目标不能转换为指针215非法类型转换struct/union/void不能转换为任何别的类型216标号用在非数组中或维数超出一个数组引用包含太大的维数或目标不是一个数组217非整数索引一个数组的维数表达式必须是char unsigned char int或unsigned int类型别的类型都是非法的218控制表达式用了void类型在一个while for或do的限制表达式中不能用类型void219long常数缩减为int一个常数表达式的值必须能用一个int类型表示220非法常数表达式期望一个常数表达式目标名变量或函数不允许出现在常数表达式中221非常数case/dim表达式一个case或一个维数[ ]必须是一个常数表达式222被零除223被零取模编译器检测到一个被零除或取模225表达式太复杂需简化一个表达式太复杂必须分成两个或多个子表达式226重复的struct/union/enum标记一个struct union或enum名早已定义227表示一个union标记一个union名称早已定义为别的类型228表示一个struct标记一个struct名早已定义为别的类型229表示一个enum标记一个enum名早已定义为别的类型230未知的struct/union/enum标记指定的struct union或enum名未定义231重复定义指定的名称已被定义232重复标号指定的标号已定义233未定义标号表示一个标号未定义有时候这个信息会在实际的标号的几行后出现这是所用的未定义标号的搜索方法引起的234{堆栈范围溢出31超过了最多31个嵌套块超出的嵌套块被忽略235参数<数字>不同类型函数声明的参数类型和函数原型中的不同236参数列表的长度不同函数声明中的参数数目和函数原型中的不同237函数早已定义试图声明一个函数体两次238重复成员239重复参数试图定义一个已存在的struct成员或函数参数240超出128个局部bit在一个函数内不能超过128个bit标量241auto段太大局部目标所需的空间超过模式的极限最大的段大小定义如下SMALL128字节COMPACT256字节LARGE65535字节242太多的初始化软件初始化软件的数目超过初始化目标的数量243字符串超出范围字符串中的字符数目超出字符串初始化的数目244不能初始化错误的类型或类试图初始化一个bit或sfr245未知的pragma跳过本行#pragma状态未知所以整行被忽略246浮点错误当一个浮点参数超出32位的范围就产生本错误32位IEEE值的范围是±1.175494E-38到±3.402823E+38247非地址/常数初始化一个有效的初始化表达式必须是一个常数值求值或一个目标名加或减去一个常数248集合初始化需要大括号给定struct或union初始化缺少大括号{}249段<名>段太大编译器检测到一个数据段太大一个数据段的最大的大小由存储空间决定250\esc值超过255一个字符串常数中的转义序列超过有效值范围最大值是255252非法八进制数指定的字符不是一个有效的八进制数252主要控制放错地方行被忽略主要控制必须被指定在C模块的开头在任何#include命令或声明前253内部错误ASMGEN\CLASS在下列情况下出现本错误一个内在函数例如_testbit_被错误激活这种情况是在没有函数原型存在和实参数目或类型错误对这种原因必须使用合适的声明文件INTRINS.H STRING.H参考第八章中的instrinsic函数Cx51确认一个内部一致性问题请接洽技术支持255switch表达式有非法类型在一个switch表达式没有合法的数据类型256存储模式冲突一个包含alien属性的函数只能包含模式标识符small函数的参数必须位于内部数据区这适用于所有的外部alien声明和alien函数例如alien plm_func(char c) large {…}产生错误256257alien函数不能重入一个包含alien属性的函数不能同时包含reentrant属性函数参数不能跳过虚拟堆栈传递这适用于所有的外部alien声明和alien函数258struct/union成员的存储空间非法非法空间的参数被忽略一个结构的成员或参数不能包含一个存储类型标识符但指针所指的目标可能包含一个存储类型例如struct vp{char code c;int xdata i; };产生错误258struct v1{char c;int xdata *i; };是正确的struct声明259指针不同的存储空间一个空指针被关联到别的不同存储空间的空指针例如char xdata *p1;char idata *p2;p1 = p2; /* 不同的存储空间 */260指针断开一个空指针被关联到一些常数值这些值超过了指针存储空间的值范围例如char idata *p1 = 0x1234; /* 结果是0x34 */261reentrant()内有bit一个可重入属性的函数的声明中不能包含bit目标例如int func1(int i1) reentrant {bit b1,b2; /* 不允许 */return(i1-1);}262using/disable不能返回bit值用using属性声明的函数和禁止中断#pragma disable的函数不能返回一个bit值给调用者例如bit test(void) using 3{bit b0;return(b0);}产生错误262263保存/恢复堆栈保存溢出/下溢#pragma save的最大嵌套深度是八级堆栈的pragma save和restore工作根据LIFO后进先出规则264内在的<内在的名称>声明/激活错误本错误表示一个内在的函数错误定义参数数目或省略号如果用标准的.H文件就不会产生本错误确认使用了Cx51所有的.H文件不要尝试对内在的库函数定义自己的原型265对非重入函数递归调用非重入函数不能被递归调用因为这样会覆盖函数的参数和局部数据如果需要递归调用需声明函数为可重入函数267函数定义需要ANSI类型的原型一个函数被带参数调用但是声明是一个空的参数列表原型必须有完整的参数类型这样编译器就可能通过寄存器传递参数和适合应用的调用机制268任务定义错误任务ID/优先级/using任务声明错误271asm/endasm控制放错地方asm和endasm声明不能嵌套endasm要求一个汇编块前面用asm开头例如#pragma asm...汇编指令...#pragma endasm272asm要求激活SRC控制在一个源文件中使用asm和endasm要求文件用SRC控制编译那么编译器就会生成汇编源文件然后可以用A51汇编273asm/endasm在包含文件中不允许在包含文件中不允许asm和endasm为了调试在包含文件不能有任何的可执行代码274非法的绝对标识符绝对地址标识符对位目标函数和局部函数不允许地址必须和目标的存储空间一致例如下面的声明是无效的因为间接寻址的范围是0x00到0xFFidata int _at_ 0x1000;278常数太大当浮点参数超出32位的浮点值范围就产生本错误32位IEEE值的范围是±1.175494E-38到±3.402823E+38279多次初始化试图多次初始化一个目标280没有使用符号/标号/参数在一个函数中声明了一个符号标号或参数但没有使用281非指针类型转换为指针引用的程序目标不能转换成一个指针282不是一个SFR引用本函数调用要求一个SFR作为参数283asmparms参数不适合寄存器参数不适合可用的CPU寄存器284<名称>在可覆盖空间函数不再可重入一个可重入函数包含对局部变量的明确的存储类型标识符函数不再完全可重入300注释未结束一个注释没有一个结束符*/301期望标识符一个预处理器命令期望一个标识符302误用#操作符字符操作符#没有带一个标识符303期望正式参数字符操作符#没有带一个标识符表示当前所定义的宏的一个正式参数名304错误的宏参数列表宏参数列表没有一个大括号逗号分开的标识符列表305string/char常数未结束一个字符串活字符常数是无效的典型的后引号丢失306宏调用未结束预处理器在收集和扩展一个宏调用的实际的参数时遇到输入文件的结尾307宏名称参数计算不匹配在一个宏调用中实际的参数数目和宏定义的参数数目不匹配本错误表示指定了太少的参数308无效的整数常数表达式一个if/elif命令的数学表达式包含一个语法错误309错误或缺少文件名在一个include命令中的文件名参数是无效的或没有310条件嵌套过多20源文件包含太多的条件编译嵌套命令最多允许20级嵌套311elif/else控制放错地方312endif控制放错地方命令elif else和endif只有在if ifdef或ifndef命令中是合法的313不能清除预定义的宏名称试图清除一个预定义宏用户定义的宏可以用#undef命令删除预定义的宏不能清除314#命令语法错误在一个预处理器命令中字符#必须跟一个新行或一个预处理器命令名例如if/define/ifdef…315未知的#命令名称预处理器命令是未知的316条件未结束到文件结尾endif的数目和if或ifdef的数目不匹配318不能打开文件文件名指定的文件不能打开319文件不是一个磁盘文件指定的文件不是一个磁盘文件文件不能编辑320用户自定义的内容本错误号未预处理器的#error命令保留#error命令产生错误号320送出用户定义的错误内容终止编译器生成代码321缺少<字符>在一个include命令的文件名参数中缺少结束符例如#include<stdio.h325正参名称重复一个宏的正参只能定义一次326宏体不能以##开始或结束##不能是一个宏体的开始或结束327宏宏名超过50个参数每个宏的参数数目不能超过50警告警告产生潜在问题的信息他们可能在目标程序的运行过程中出现警告不妨碍源文件的编译警告在列表文件中生成信息警告信息用下面的格式*** WARNING number IN LINE line OF file: warning message这里number错误号line在源文件或包含文件中的对应行号file错误产生的源或包含文件名warning message警告的内容下表按号列出了警告警告信息包括一个主要的内容和可能的原因和纠正措施173缺少返回表达式一个函数返回一个除了int类型以外的别的类型的值必须包含一个返回声明包括一个表达式为了兼容旧的程序对返回一个int值的函数不作检查182指针指向不同的目标一个指针关联了一个不同类型的地址185不同的存储空间一个目标声明的存储空间和前面声明的同样目标的存储空间不同196存储空间可能无效把一个无效的常数值分配给一个指针无效的指针常数是long或unsigned long编译器对指针采用24位3字节低16位代表偏移高8位代表选择的存储空间198sizeof返回零一个目标的大小计算结果为零如果目标是外部的或如果一个数组的维数没有全知道则值是错误的206缺少函数原型因为没有原型声明被调用的函数是未知的调用一个未知的函数通常是危险的参数的数目和实际要求不一样如果是这种情况函数调用不正确没有函数原型编译器不能检查参数的数目和类型要避免这种警告应在程序中包含函数的原型函数原型必须在函数被调用前声明注意函数定义自动生成原型209实参太少在一个函数调用中包含太少的实参219long常数被缩减为int一个常数表达式的值必须能被一个int类型所表示245未知的pragma本行被忽略#pragma声明是未知的因此整行程序被忽略258struct/union成员的存储空间方法参数的存储空间被忽略一个结构的成员或一个参数不能指定存储类型但是指针所指的目标可以包含一个存储类型例如struct vp{ char code c;int xdata i; };产生警告258struct v1{ char c;int xdata *i; };对struct是正确的声明259指针不同的存储空间两个要比较的指针没有引用相同的存储类型的目标260指针折断把一个指针转换为一个更小偏移区的指针转换会完成但大指针的偏移会折断来适应小指针261bit在重入函数一个reentrant函数不能包含bit因为bit标量不能保存在虚拟堆栈中265名称对非重入函数递归调用发现对一个非重入函数直接递归这可能是故意的但对每个独立的情况进行功能性检查通过生成的代码间接递归由连接/定位器检查271asm/endams控制放错地方asm和endasm不能嵌套endasm要求一个以asm声明开头的汇编块例如#pragma asm...汇编指令...#pragma endasm275表达式可能无效编译器检测到一个表达式不生成代码例如void test(void) {int i1,i2,i3;i1,i2,i3; /* 死表达式 */i1 << i3; /* 结果未使用 */}276常数在条件表达式编译器检测到一个条件表达式有一个常数值在大多数情况下是一个输入错误例如void test(void) {int i1,i2,i3;if( i1 = 1) i2 = 3; /* 常数被赋值 */while( i3 = 2); /* 常数被赋值 */}277指针有不同的存储空间一个typedef声明的存储空间冲突例如typedef char xdata XCC; /* 存储空间xdata */typedef XCC idata PICC; /* 存储空间冲突 */280符号/标号未使用一个符号或标号定义但未使用307宏名称参数计算不匹配一个宏调用的实参的数目和宏定义的参数数目不匹配表示用了太多的的参数过剩的参数被忽略317宏名称重新定义无效一个预定义的宏不能重新定义或清除参考138页的预定义宏常数322未知的标识符在一个#if命令行的标识符未定义等效为FALSE323期望新行发现多余字符一个#命令行正确但包含多余的非注释字符例如#include <stdio.h> foo。
初学者学习C51的一些误区和注意事项

初学者学习C51的一些误区和注意事项
这里讲述一些初学者学习C51 的一些误区和注意事项。
高手的特别应用不包括在内。
1)C 忌讳绝对定位。
常看见初学者要求使用_at_,这是一种谬误,把C 当作ASM 看待了。
在C 中变量的定位是编译器的事情,初学者只要定义变量和变量的作
用域,编译器就把一个固定地址给这个变量。
怎么取得这个变量的地址?要用指针。
比如unsigned char data x;后,x 的地址就是x,
你只要查看这个参数,就可以在程序中知道具体的地址了。
所以俺一看见要使用绝对定位的人,第一印象就是:这大概是个初学者。
2)设置SP 的问题。
原因和1 差不对,编译器在把所有变量和缓冲区赋予地址后,自动把最后一个字节开始的地方,作为SP 的开始位置,所以初学者是不必
要去理会的。
这体现C 的优越性,很多事情C 编译时候做了。
3)用C 的主程序结构:
#include reg52.h
void main(void)
{
while(1);
}
这是个最小的成功的C 程序,包括头部文件和程序主体。
头部文件的名词解释:引用的外部资源文件,这个文件包括了硬件信息和外部模块提供的可使用的函数和变量的说明。
可以用文本方。
单片机C51语言及程序设计

单片机C51语言及程序设计单片机是一种微型计算机芯片,通常用于控制和执行各种电子设备中的任务。
单片机C51语言是一种基于C语言的编程语言,它在单片机开发中被广泛应用。
本文将对单片机C51语言及程序设计进行介绍。
一、单片机C51语言简介单片机C51语言是一种基于C语言的嵌入式编程语言,它是Intel公司为其8051系列单片机提供的编程语言。
C51语言与C语言的语法相似,但是在一些底层操作和特殊功能上有所区别。
使用C51语言编写的程序可以在8051系列单片机上直接运行,实现各种控制和功能。
C51语言的特点包括高效的编译器、丰富的库函数、快速的速度和较小的存储空间占用。
它可以利用C语言的各种高级特性进行程序设计,同时也支持直接对单片机的硬件进行底层操作。
二、单片机C51语言程序编写1.编译与烧录环境2.基本语法和数据类型C51语言的基本语法与C语言相似。
它支持各种数据类型,包括整数、浮点数、字符等。
同时,C51语言还定义了一些特殊的数据类型和关键字,如sfr(特殊功能寄存器)、xdata(扩展数据存储器)等。
3.控制语句和函数C51语言支持各种控制语句和函数,如条件语句(if-else、switch-case)、循环语句(for、while)、函数定义等。
通过这些语句和函数,我们可以实现复杂的控制逻辑和算法。
4.寄存器和端口操作单片机的核心是CPU和各种寄存器。
C51语言提供了一些特殊的语法和关键字,可以直接访问和操作寄存器。
通过这些操作,我们可以实现对单片机硬件的底层控制。
例如,下面的代码演示了如何使用C51语言对LED灯进行控制:sfr P0 = 0x80; // 特殊功能寄存器,用于控制P0口#define LED_PIN P0_0 // 使用宏定义定义LED的引脚void maiLED_PIN=0;//将LED引脚电平设为低电平while(1)LED_PIN=1;//将LED引脚电平设为高电平delay(1000); // 延时1秒LED_PIN=0;//将LED引脚电平设为低电平delay(1000); // 延时1秒}在上面的代码中,我们通过特殊功能寄存器P0和宏定义LED_PIN,定义了与LED相关的引脚和寄存器。
基于KeilC51编译器的程序优化设计本月修正简版

基于KeilC51编译器的程序优化设计基于Keil C51 编译器的程序优化设计引言Keil C51 是一款常用的嵌入式 C 语言编译器,广泛应用于8051 系列单片机的开发中。
在实际项目中,程序的运行效率往往是至关重要的。
在编写程序时,我们需要考虑如何通过优化设计来提高程序的运行效率,减少资源占用。
本文将介绍一些基于 Keil C51 编译器的程序优化设计技巧。
1. 使用适当的数据类型在编写程序时,选择合适的数据类型对于程序的性能影响很大。
使用过大的数据类型会浪费内存空间和处理器资源,而使用过小的数据类型则可能导致数据溢出或精度丢失。
我们应该根据实际需求选择合适的数据类型。
2. 减少变量的使用过多的变量会增加程序的内存消耗和处理器使用,降低程序的效率。
在设计程序时,应尽量减少变量的使用。
可以通过重用变量、合并变量以及使用位域等方式来减少变量的数量。
3. 使用位运算代替乘除运算位运算相对于乘除运算来说,更加高效。
在程序中,如果遇到频繁使用乘除运算的地方,可以考虑使用位运算代替,从而提高程序的效率。
4. 使用宏定义和内联函数宏定义和内联函数可以减少函数调用的开销,提高程序的效率。
宏定义在编译时会直接展开,而内联函数会直接将函数的代码插入到调用的地方。
在一些短小的函数或代码块中,可以使用宏定义或内联函数来提高程序的效率。
5. 使用优化选项Keil C51 编译器提供了一些优化选项,可以通过设置编译器的优化级别来优化程序的代码。
优化级别越高,的代码越有效率,但也会增加编译时间。
在不影响开发效率的前提下,可以适当调整编译器的优化级别,提高程序的运行效率。
6. 减少循环次数循环是程序中常见的结构之一,在设计循环时,应尽量减少循环次数,减少程序运行的时间。
可以通过优化循环结构、合并循环、使用循环展开等方式来减少循环次数,从而提高程序的效率。
7. 使用中断优化Keil C51 编译器提供了一些针对中断的优化选项,可以通过设置中断优化选项来提高中断的响应速度和处理效率。
单片机C语言编程中几种常见问题解析

龙源期刊网 单片机C语言编程中几种常见问题解析作者:韩彩霞来源:《软件导刊》2013年第07期摘要:现在的单片机仿真器普遍支持C语言程序的调试,为单片机使用C语言提供了便利条件(简称C51)。
C语言相对汇编语言来说,能直接对单片机硬件进行操作,既有高级语言的特点,又有汇编语言的特点。
讨论了C51编程中需要注意的事项,并结合Keil C 仿真软件给出相应说明。
关键词关键词:单片机;C51;Keil C中图分类号:TP301 文献标识码:A 文章编号文章编号:16727800(2013)0070047031 整型(字)数据在C51中的存储问题在C51中常用的数据类型有整型(int)、字符型(char)。
其中,整型数据就是人们常说的字(16位),字符型数据就是字节(8位)。
通过图1和图2来说明这两种数据在汇编和C51中的存储方式。
由图1和图2可知,地址0001H和0002H中分别存储字符型数据12H和34H,这两种编程语言对于字符型数据来说存储方式是相同的。
但是对于整型数据就不同了,一个是整型数据3412H,另一个是整型数据1234H。
在汇编语言中整型数据存储方式是:高字节存高地址中,低字节存低地址中;而对于整型数据在C51中存储方式是:高字节存低地址中,低字节存高地址中。
下面通过Keil C软件调试来说明这一问题。
参考文献:[1] 姜志海.单片机的C语言程序设计及应用[M].北京:电子工业出版社,2011.[2] 邹益民.单片机C语言教程[M].北京:中国石化出版社,2011.[3] 张蕊.C语言程序设计教程[M].武汉:华中科技大学出版社,2019.责任编辑(责任编辑:余晓)。
单片机指令编程的常见错误与解决方法

单片机指令编程的常见错误与解决方法在单片机指令编程过程中,往往会遇到各种问题和错误。
这些问题可能导致程序无法正常运行或者出现意料之外的结果。
本文将介绍一些常见的错误,以及相应的解决方法,帮助程序员更好地进行单片机指令编程。
一、编码错误编码错误是指在编写指令时出现的错误,包括语法错误和逻辑错误。
语法错误是最基本的错误,常见的有拼写错误、缺少分号等。
逻辑错误则是指程序的逻辑不正确,导致程序无法按照预期的方式执行。
解决方法:1. 仔细检查代码,查找并修复语法错误。
2. 使用调试工具,逐步执行代码,观察程序的执行过程,找出逻辑错误的根源。
3. 采用模块化编程方法,将程序划分为多个相对独立的模块,降低程序的复杂性,便于调试和维护。
二、寄存器配置错误单片机中的寄存器是非常重要的,它们用来存储程序的运行状态和数据。
配置寄存器时,如果设置不正确,可能导致程序无法正常运行。
解决方法:1. 仔细查阅单片机的手册或者数据手册,确保对寄存器的配置有充分的了解。
2. 逐个检查寄存器的配置,确保每个寄存器的值都正确设置。
3. 使用调试工具,观察寄存器的状态,排除配置错误的可能性。
三、时钟设置错误单片机的时钟是程序运行的基础,对于某些需要实时操作的程序尤为重要。
时钟设置错误可能导致程序时序不正确,无法正常执行。
解决方法:1. 确保时钟源的选择正确,并选择合适的分频系数。
2. 配置好时钟控制寄存器,确保时钟的频率满足程序运行的要求。
3. 使用专业的时钟分析工具,对时钟信号进行分析和调试,确保时钟信号的准确性和稳定性。
四、中断处理错误中断是单片机的重要功能,可以实现对外部事件的响应。
如果中断处理错误,可能导致程序的执行流程混乱,无法正常处理中断事件。
解决方法:1. 确保中断向量表的设置正确,每个中断向量都与对应的中断服务程序相对应。
2. 配置中断控制器,使能或禁止某些中断,确保中断的优先级设置正确。
3. 定期检查中断服务程序的正确性,确保程序在中断发生时能够正确响应。
c51程序设计心得

c51程序设计心得
C51程序设计是指基于C51单片机的嵌入式系统开发。
在进行C51程序设计时,我认为有几个重要的方面需要考虑和总结心得。
首先,了解C51单片机的特性和指令集是非常重要的。
C51单片机是一种经典的8位单片机,具有特定的指令集和内部外设,包括GPIO、定时器、串口等。
熟悉这些特性可以帮助我们更好地利用C51单片机的功能进行程序设计。
其次,合理的程序结构和模块化设计是C51程序设计的关键。
在编写C51程序时,我们应该尽量遵循模块化的设计原则,将程序分解为多个模块,每个模块只负责特定的功能,这样不仅有利于代码的维护和扩展,也有利于团队协作和代码复用。
另外,对于C语言的应用也是C51程序设计的重要部分。
C语言是一种高级语言,可以帮助我们更快速地编写程序,并且具有良好的可移植性。
在C51程序设计中,我们可以充分利用C语言的特性,比如结构体、指针等,来简化程序设计和提高代码的可读性。
此外,调试和优化也是C51程序设计中需要重点关注的问题。
由于嵌入式系统的特殊性,对程序的调试和优化需要更加细致和深入。
我们可以通过单步调试、使用适当的调试工具和仪器来帮助我们找出程序中的问题,并且针对性地进行优化,以提高程序的性能和稳定性。
总的来说,C51程序设计需要我们全面理解单片机的特性,合理设计程序结构,熟练运用C语言,并且注重调试和优化。
通过不断的实践和总结,我们可以不断提高自己的C51程序设计能力,开发出高质量的嵌入式系统。
KEIL C51 常见问题集合

Keil Cx51编译器编程基本原则和代码的优化 ——和复杂声明的理解Copyleft2009 by高飞电子经营部(官网地址,点击之前请确认。
)图1 51基本内核的结构框图以上各部分通过内部总线相连接。
在很多情况下,单片机还要和外部设备或外部存储器相连接,连接方式采用三总线(地址、数据、控制)方式,但在51单图2 普通51单片机的存储器组织结构空间名称 地址范围 说明 DATA D:00H~D:7FH 片内RAM直接寻址BDATA D:20H~D:2FH 片内RAM位寻址IDATA I:00H~I:FFH 片内RAM间接寻址XDATA X:0000H~X:FFFFH 64KB片外RAM数据区CODE C:0000H~C:FFFFH 64KB片外ROM代码区 BANK0~BANK31B0:0000~B0:FFFFH...B31:0000~B31:FFFFH分组代码区,最大可扩展32x64KB ROM表1 普通51单片机存储器空间分配表高飞出品必属精品,版权所有欢迎转载欢迎光临我的淘宝小店-高飞电子经营部/图3 新型51单片机的扩展存储器组织结构空间名称 地址范围 说明DATA D:00H~D:7FH 片内RAM 直接寻址 BDATA D:20H~D:2FH 片内RAM 位寻址 IDATA I:00H~I:FFH 片内RAM 间接寻址 XDATA X:0000H~X:FFFFH 64KB 片外RAM 数据区 CODE C:0000H~C:FFFFH 64KB 片外ROM 代码区 HCONST(ECODE) C:0000H~C:FFFFFFH 16MB 扩展片外ROM 常数区(对Dallas390可用做代码区)BANK0~BANK31 B0:0000~B0:FFFFH . . . B31:0000~B31:FFFFH分组代码区,最大可扩展32x64KB ROM表2 新型80C51单片机扩展存储器空间分配表6 ***WARNING 6 :XDATA SPACE MEMORY OVERLAP FROM : 0025H TO: 0025H说明外部存储器ROM的0025H 重复定义地址。
单片机的c51语言编程及仿真方法

单片机的c51语言编程及仿真方法一、C51语言的基本概念和编程方法C51语言是一种面向单片机的高级编程语言,广泛应用于嵌入式系统的开发。
C51语言具有结构化、模块化和可移植性等特点,使得程序的编写更加简便和灵活。
在C51语言中,程序由函数和变量组成。
函数是C51程序的基本执行单位,通过函数的调用和返回实现程序的流程控制。
变量是存储数据的单元,可以是整型、字符型或者数组等不同类型的数据。
C51语言的编程方法主要有以下几点:1. 硬件初始化:在C51程序中,首先需要进行硬件的初始化工作,包括IO口的配置、定时器的设置、中断的使能等。
这些初始化工作需要在程序的开头进行,并且只需要执行一次。
2. 主函数编写:主函数是C51程序的入口函数,程序从主函数开始执行。
在主函数中,可以定义局部变量、调用其他函数和执行各种操作。
主函数一般包含一个无限循环,以保持程序的持续运行。
3. 函数的定义:除了主函数外,C51程序还可以定义其他函数,用于实现特定的功能。
函数的定义包括函数名、返回值类型、参数列表和函数体。
函数可以被主函数或其他函数调用,以实现不同的功能模块。
4. 控制语句的使用:C51语言支持多种控制语句,包括顺序结构、条件结构和循环结构。
通过这些控制语句,可以实现程序的各种流程控制,例如条件判断、循环执行等。
5. 编译和下载:编写完C51程序后,需要使用编译器将程序转换为机器语言,并生成可执行文件。
然后,通过下载工具将可执行文件下载到单片机中,以使程序在单片机上运行。
二、C51的仿真方法C51的仿真是指在计算机上模拟单片机的运行环境,以便在不实际连接硬件的情况下进行程序的调试和验证。
C51的仿真方法主要有以下几种:1. Keil C51仿真器:Keil C51是一款常用的单片机开发工具,提供了强大的仿真功能。
通过Keil C51仿真器,可以在计算机上运行单片机程序,并通过仿真界面实时监测程序的执行情况。
Keil C51仿真器支持单步调试、断点调试等功能,方便程序的调试和验证。
单片机C语言编程的常见问题分析

单片机C语言编程的常见问题分析单片机C语言编程是一项关键任务,也是一项复杂的任务。
在整个过程中难免会出现一些问题。
接下来我们将分析单片机C语言编程的常见问题,并提供解决方案。
1. 内存问题单片机C语言编程时,由于内存数量有限,因此经常会出现内存不足的问题。
这种情况下,您可以尝试压缩代码并删除不必要的宏和库。
此外,您还可以考虑使用更高端的单片机。
2. 时序问题单片机C语言编程时,时序问题往往非常重要。
如果出现时序问题,将会导致设备不能按照预期运行。
您可以尝试使用定时器和计数器调整时序。
此外,考虑使用更快的单片机可能有助于解决一些时序问题。
3. 电源问题电源问题是单片机C语言编程中最普遍的问题之一。
当电源电压不稳定或电源噪声太大时,单片机可能会崩溃或不正常运行。
您可以使用电源滤波器或稳压器来处理电源问题。
此外,为了防止来自设备的噪声干扰,建议使用屏蔽绕线或扼流圈,以及被屏蔽的电缆。
4. 外设接口问题单片机C语言编程中,外设接口协议往往非常关键。
如果协议未正确实现,那么设备将无法正常工作。
解决外设接口问题的最佳方法是遵循设备生产商的建议和规格。
您应遵循正确的接线和连接方式。
此外,您还应该了解有关数据传输时序和其他配置数据的信息。
5. 硬件问题硬件问题可以导致单片机无法正常运行,即使编写的代码无错。
如果您的硬件出现问题,请确保它已经正确接线并使用正确的电压,同时进行逐步排除的测试方法。
此外,您可能需要检查单片机是否被损坏或是否需要换一个更高配置的设备。
总之,解决单片机C语言编程中的常见问题需要有耐心、细致和专业的技能,这样才能使您的设备正常工作。
如果您遇到了无法解决的问题,可以参考设备生产商提供的文档或咨询相关的开发者社群。
KEILC51代码优化详细分析

KEILC51代码优化详细分析阅读了《单片机与嵌入式系统应用》2005年第10期杂志《经验交流》栏目的一篇文章《Keil C51对同一端口的连续读取方法》(原文)后,笔者认为该文并未就此问题进行深入准确的分析文章中提到的两种解决方法并不直接和简单。
笔者认为这并非是Keil C51中不能处理对一个端口进行连续读写的问题,而是对Kei1 C51的使用不够熟悉和设计不够细致的问题,因此特撰写本文。
本文中对原文提到的问题,提出了三种不同于原文的解决方法。
每种方法都比原文中提到的方法更直接和简单,设计也更规范。
(无意批评,请原文作者见谅)1 问题回顾和分析原文中提到:在实际工作中遇到对同一端口反复连续读取,Keil C51编译并未达到预期的结果。
原文作者对C编译出来的汇编程序进行分析发现,对同一端口的第二次读取语句并未被编译。
但可惜原文作者并未分析没有被编译的原因,而是匆忙地采用一些不太规范的方法试验出了两种解决办法。
对此问题,翻阅Keil C51的手册很容易发现:KeilC51的编译器有一个优化设置,不同的优化设置,会产生不同的编译结果。
一般情况缺省编译优化设置被设定为8级优化,实际最高可设定为9级优化:1. Dead code elimination。
2.Data overlaying。
3.Peephole optimization。
4.Register variables。
mon subexpression elimination。
6.Loop rotation。
7.Extended Index Access Optimizing。
8.Reuse Common Entry Code。
mon Block Subroutines。
而以上的问题,正是由于Keil C51编译优化产生的。
因为在原文程序中将外设地址直接按如下定义:unsigned char xdata MAX197 _at_ 0x8000采用_at_将变量MAX197定义到外部扩展RAM 指定地址0x8000。
C51中printf使用注意

C51中printf使⽤注意C51中printf使⽤注意printf函数是STDIO.H下的其中⼀个输出函数在C51中直接使⽤是不⾏的,⽆法输出所想的显⽰内容,需要通过设置串⼝,在串⼝输出显⽰内容。
下⾯是设置串⼝的程序:SCON = 0x50; //串⼝⽅式1,允许接收TMOD = 0x20; //定时器1定时⽅式2TCON = 0x40; //设定时器1开始计数TH1 = 0xFD; //11.0592MHz 9600波特率TI = 1;TR1 = 1; //启动定时器C51标准串⼝发送程序(已C8051F120为例,注意C8051F120特殊功能寄存器是分页的)/***********************************************************函数名称:send_char_com函数功能:向串⼝发送⼀字节字符⼊⼝参数:unsigned char sendByte ⼀个字节字符(8 bit)出⼝参数:⽆备注:***********************************************************/void send_char_com(unsigned char sendByte){char SFRPAGE_SAVE = SFRPAGE; //⽤到TI0(SCON0.1)SFR页:0SFRPAGE = UART0_PAGE;SBUF0=sendByte;while (TI0== 0); //等待发送完毕TI0= 0; //清发送中断标志TI0SFRPAGE = SFRPAGE_SAVE;}/***********************************************************函数名称:send_char_com函数功能:向串⼝发送⼀个字符串⼊⼝参数:unsigned char *str 字符串数组⾸地址unsigned int strlen 该字符串长度出⼝参数:⽆备注:***********************************************************/void send_string_com( unsigned char *str, unsigned int strlen){unsigned int k= 0 ;do {send_char_com(*(str + k));k++;}while (k < strlen);}在C51中直接使⽤printf⽐⾃⼰编个串⼝发送字符串的函数⽅便,但有⼏个问题要注意的。
分享:KEILC51编译问题MULTIPLEPUBLICDEFINITIONS重复定义

分享:KEILC51编译问题MULTIPLEPUBLICDEFINITIONS
重复定义
KEILC51编译问题MULTIPLE PUBLIC DEFINITIONS重复定义
c/c++语言中有很多地方要用到extern,但是如果没有真正的了解它的意义,会给编程带来很大的麻烦,为了使大家少走弯路,特祥细的说明一下。
对于比较小的程序,一般只有一个c文件和一个头文件,全局变量我们通常会直接定义在c文件中,在程序之前加int i定义。
如果要在头文件中定义有以下两种方法:用extern来声明:extern int i;这一句只是对变量i进行声明,在c文件的程序之前必须加上int i进行定义。
extern int i=0;这一句声明和定义都做了。
对于大一点的程序,有很多c文件和头文件,这个时候全局变量就必须在头文件中声明(不需要初始化),然后在一个c文件中定义(该初始化的要初始化)。
如果在头文件中定义,则编译的时候会出现重复定义的错误。
如果只有头文件中声明就会出现没有定义有警告。
*** ERROR LXX: MULTIPLE PUBLIC DEFINITIONS
SYMBOL: K
MODULE: 222.obj (222)
出现上述错误则是因为变量k重复定义,把你的头文件中的变量定义前加extern(只是变量声明不用初始化),再在某一个你要调用该变量的c文件的程序之前再定义(注意第一个调用的c文件要负责附带初始化该变量,其他调用的c文件就不需要初始化过程啦)。
我总结的KEIL51调试的错误总结

KEIL51调试时一些的错误总结(1)提示无M51文件编译时候提示:F:\...\XX.M51File has been changed outside the editor, reload ?------解决方法:重新生成项目,产生STARTUP.A51即可。
(2)L15重复调用***WARNING L15: MULTIPLE CALL TO SEGMENTSEGMENT: ?PR?SPI_RECEIVE_WORD?D_SPICALLER1: ?PR?VSYNC_INTERRUPT?MAINCALLER2: ?C_C51STARTUP如果函数可以在其执行时被调用,则情况会变得更复杂一些。
这时可以采用以下几种方法:1.主程序调用该函数时禁止中断,可以在该函数被调用时用#pragma disable语句来实现禁止中断的目的。
必须使用OVERLAY指令将该函数从覆盖分析中除去。
2.复制两份该函数的代码,一份到主程序中,另一份复制到中断服务程序中。
3.将该函数设为重入型。
例如:void myfunc(void) reentrant {...}这种设置将会产生一个可重入堆栈,该堆栈被被用于存储函数值和局部变量,用这种方法时重入堆栈必须在STARTUP.A51文件中配置。
这种方法消耗更多的RAM并会降低重入函数的执行速度。
(3)L16无调用*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESSSEGMENT: ?PR?_COMPARE?TESTLCD说明:程序中有些函数例如COMPARE(或片段)以前(调试过程中)从未被调用过,或者根本没有调用它的语句。
这条警告信息前应该还有一条信息指示出是哪个函数导致了这一问题。
只要做点简单的调整就可以。
不理它也没什么大不了的。
解决方法:去掉COMPARE()函数或利用条件编译#if …..#endif,可保留该函数并不编译。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C51语言应用编程的若干问题
在研制单片机应用系统时,汇编语言是一种常用的软件工具。
它能直接操作硬件,指令的执行速度快。
但其指令系统的固有格式受硬件结构的限制很大,且难于编写与调试,可移植性也差。
随着单片机硬件性能的提高,其工作速度越来越快,因此在编写单片机应用系统程序时,更着重于程序本身的编写效率。
而Franklin C51交叉编译器是专为80C51系列单片机设计的一种高效的C语言编译器,使用它可以缩短开发周期,降低开发成本,而且开发出的系统易于维护,可靠性高,可移植性好,即使在代码的使用效率上,也完全可以和汇编语言相比,因此目前它已成为开发80C51系列单片机的流行工具。
1 C51语言程序设计的基本技巧
C语言是一种高级程序设计语言,它提供了十分完备的规范化流程控制结构。
因此采用C51语言设计单片机应用系统程序时,首先要尽可能地采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,易于调试和维护。
对于一个较大的程序,可将整个程序按功能分成若干个模块,不同的模块完成不同的功能。
对于不同的功能模块,分别指定相应的入口参数和出口参数,而经常使用的一些程序最好编成函数,这样既不会引起整个程序管理的混乱,还可增强可读性,移植性也好。
在程序设计过程中,要充分利用C51语言的预处理命令。
对于一些常用的常数,如TRUE,FALSE,PI以及各种特殊功能寄存器,或程序中一些重要的依据外界条件可变的常量,可采用宏定义"#define"或集中起来放在一个头文件中进行定义,再采用文件包含命令"#include"将其加入到程序中去。
这样当需要修改某个参量时,只须修改相应的包含文件或宏定义,而不必对使用它们的每个程序文件都作修改,从而有利于文件的维护和更新。
现举例说明如下:
例1 对于不同的单片机晶振,程序取不同的延时时间,而且可根据外界条件的变化修改延时时间的长短。
对于这样的程序,可利用宏定义和条件编译来实现。
程序如下:
#define flag 1
#ifdef flag==1
#define fosc 6M
delay=10;
#elif flag ==0
#define fosc 8M
delay=12;
#else
#define fosc 12M
delay=20;
#endif
main()
{
for(I=0;I<delay;I++);
}
这样源程序不作任何修改就可适用于不同时钟频率的单片机系统,并可根据情况的不同取不同的delay值,完成不同的目的。
2 C51语言与汇编语言程序的混合编程
C51编译器能对C语言源程序进行高效率的编译,生成高效简
洁的代码,在绝大多数场合采用C语言编程即可完成预期的目的。
但有时为了编程直观或某些特殊地址的处理,还须采用一定的汇编语言编程。
而在另一些场合,出于某种目的,汇编语言也可调用C语言。
在这种混合编程中,关键是参数的传递和函数的返回值。
它们必须有完整的约定,否则数据的交换就可能出错。
下面就以力源公司的10位串行A/D转换器TLC1549 为例说明C语言程序与汇编语言程序的调用。
图1 TLC1549管脚图
1549的管脚图和时序图分别如图1和图2所示,假定DATA OUT接P1.0,接P1.1,CLOCK接P1.2。
1549的具体特性请查阅有关资料。
图2 TLC1549时序图
例2 C语言程序与汇编语言程序的调用,其子程序如下:
PUBLIC AD ;入口地址
SEG_AD SEGMENT CODE;程序段
RSEG SEG_AD
USING 0
AD: MOV R6,#00
MOV R7,#00
SETB P1.1
ACALL DELAY
CLR P1.1
ACALL DELAY
MOV R0,#10
RR0: S ETB P1.2
NOP
CLR P1.2
DJNZ R0,RR0
ACALL DELAY
MOV 30H,R6 ;A/D转换的高
;两位保存在R6中
ACALL CIR
MOV R6,30H
SETB P1.2
NOP
CLR P1.2
MOV 30H,R6
ACALL CIR
MOV R6,30H
MOV R0,#8 ;A/D转换的低
;8位保存在R7中
RR2: S ETB P1.2
NOP
CLR P1.2
MOV 30H,R7
ACALL CIR
MOV R7,30H
DJNZ R0,RR2
RET
CIR: CLR C
MOV C,P1.0
MOV A,30H
RLC A
MOV 30H,A
RET
END
在以上程序中,函数的返回值为一无符号整型数,根据调用规则,返回值的高位必须在R6中,低位在R7中,这样才可保证数据的传递不出错。
另外,在调用过程中,必须注意寄存器的入栈。
这样在以后用到A/D转换时,在C语言中调用汇编语言子程序AD()即可。
3 C51中断处理过程
C51编译器支持在C源程序中直接开发中断过程,因此减轻了使用汇编语言的繁琐工作,提高了开发效率。
中断服务函数的完整语法如下:
void 函数名(void)[模式]
[再入]interrupt n [using r]
其中n(0~31)代表中断号。
C51编译器允许32个中断,具体使用哪个中断由80C51系列的芯片决定。
r(0~3)代表第r组寄存器。
在调用中断函数时,要求中断过程调用的函数所使用的寄存器组必须与其相同。
"再入"用于说明中断处理函数有无"再入"能力。
C51编译器及其对C语言的扩充允许编程者对中断所有方面的控制和寄存器组的使用。
这种支持能使编程者创建高效的中断服务程序,用户只须在C语言下关心中断和必要的寄存器组切换操作。
例3 设单片机的f osc=12MHz,要求用T0的方式1编程,在P1.0脚输出周期为2ms的方波。
用C语言编写的中断服务程序如下:
#include <reg51.h>
sbit P1_0=P1^0;
void timer0(void)interrupt 1 using 1 {
/*T0中断服务程序入口*/
P1_0=!P1_0;
TH0=-(1000/256); /*计数初值重装*/
TL0=-(1000%256);
}
void main(void)
{
TMOD=0x01; /*T0工作在定时器方式1*/
P1_0=0;
TH0=-(1000/256); /*预置计数初值*/
TL0=-(1000%256);
EA=1; /*CPU开中断*/
ET0=1; /*T0开中断*/
TR0=1; /*启动T0*/
do{}while(1);
}
在编写中断服务程序时必须注意不能进行参数传递,不能有返回值。
4 结论
C51编译器不但可以缩短单片机控制系统的开发周期,而且易于调试和维护。
此外,C51语言还有许多强大的功能,如提供丰富的库函数供用户直接调用,完整的编译控制指令为程序调试提供必要的符号信息等等。
总之,C51语言是广大单片机开发人员的强有力的工具。