写KeilC遇到的坑

写KeilC遇到的坑

1、跟vs中不同,keilC中的的变量必须声明在最前,不然就出错。

2、KeilC中的错误提示功能实在是很弱。没有办法精确到具体是哪个具体的变量或标点符号出问题。

3、KeilC中的unsigned int能表示的数太小,只能有五位数,导致烧到单片机上的时候,数码管显示有问题。

unsigned char,8位,最大值255
unsigned int,16位,最大值65535

4、8针的引脚只要用unsigned char就可以控制,因为unsigned char 是8位的。

5、在LCD1602输出了脏数据。

 1 #include<reg51.h>
 2 #define uchar unsigned char
 3 #define uint unsigned int
 4 uchar code table[]="Hello World!";
 5 uchar code table1[]="I am a boy!";
 6 ///此处省略了一系列的函数定义
 7 void main()
 8 {
 9         int num;
10     init();
11     write_command(0x80+0x10);
12     for(num=0;num<20;num++)
13     {
14         write_data(table[num]);
15         delay(5);
16     }
17     //此处省略了一些无关内容
18 }

在以上代码段中,我们期望在LCD1602的第一行输出”Hello World!       “,注意这个输出后面是空白的,但是输出了”Hello World!       **** I am a”(***代表乱码)。这就有点无奈了。调了好久,一开始以为是ram里面有暂存的数据,单片机断电后,再试还是不行。后面联想到编译原理中,两个字符串table和table1都是用code定义的数组,他们存储位置是程序存储器。又因为table1定义的位置正好在table的下面,所以当以上代码行12对应处遍历table数组超出table本身的索引时,自然就输出了table1的内容,从而造成脏数据。

 

6、头文件的定义。

①当我们定义头文件的时候,最后不要在头文件里面定义define uchar unsigned char 这类的东西,因为当引用了两次头文件或者不同的头文件里面都有同样的define的时候,程序会出问题。

②当定义头文件的时候,为了避免二次引用造成重复定义,最好在头文件上#ifndef __I2C_H__  #define __I2C_H__ 、#endif(其中__I2C_H__是自己定义的一个名称如以下代码段所示参考链接

 

 1 #ifndef __I2C_H__
 2 #define __I2C_H__
 3 
 4 //========函数区============================================
 5 extern void I2C_start();  //开始信号
 6 extern void I2C_stop();   //停止
 7 extern void I2C_respons();  //应答
 8 extern void I2C_write_byte(unsigned char date);
 9 extern unsigned char I2C_read_byte();
10 extern void I2C_write_address(unsigned char address,unsigned char date);
11 extern unsigned char I2C_read_address(unsigned char address);
12 //========函数区结束============================================
13 #endif

 

 7、按键反应很慢。

下面的程序是一个按下独立按键,然后在LED屏幕上显示当前计数值的程序。程序要实现:当按下独立按键1的时候,等待。当再次按下,程序往下运行。我发现当我按下,程序可以很快地反应;但是再次按下想让他运行的时候,却要等待大概3~5秒的时间。细看以下代码段加灰的地方和中断函数,终于发现了原因。原来,当忙等待的时候,中断函数int0()中的Count还在不断计数,也就是Count可能大于20,那么就不满足Count==20这个条件。而要等再次满足Count==20,则要等待Count计满重新归零(注意Count是无符号数,无符号数计满的时候自动归零)。

#include<reg51.h>
unsigned char Count=0;
/***********************************************************
    重新计数
***********************************************************/
void ReCount(){
    Count=0;  //开始下一轮1s的计时
    TH0=T_High_50ms;// 计算初值,并将其写入TH0、TL0或TH1、TL1。
    TL0=T_Low_50ms;
}
void main()
{
    
//去掉不必要的初始化函数
while(1){
Waiting();
//一个忙等待函数,当按下独立按键1的时候,等待。当再次按下, //程序往下运行 if(Count==20){ //定时器0 1s时间到 ReCount(); //……省略做其他事情的函数 } } } void int0() interrupt 1//定时/计数器T0中断 { Count++; }

 8、强制转化的问题

除了强制转化成bit型是取高位外(代码段1),其他从位数少到位数多类型的强制类型转换都是取低位。

 1 unsigned char aChar=0x00;//除了强制转化成bit型是取高位外
 2 unsigned int aInt=0xaa55;
 3 aChar=(unsigned char)aInt;
 4 //结果:aChar=0x55
 5 
 6 ///
 7 bit aBit;
 8 unsigned char aChar=0x01; //其他从位数少到位数多类型的强制类型转换都是取低位。
 9 aBit=(bit)aChar;
10 //结果:aBit=0;

9、全局变量定义在头文件(*.h)或源文件(*.c)的思考。

看了一些代码,似乎在头文件的定义中都尽量地避免了对全局变量的定义。我想头文件是给人引用的,也就是这部分的内容必须暴露,为了函数的封装性更好,更好的方法就是将全局变量尽可能封装在源文件 (*.c)。这样,使用者不会因为头文件中含有全局变量而感到困惑,也不用因为全局变量而去了解整个C语言函数库的实现细节。

10、C#和Java都是支持函数的重载的,但是C语言中不支持函数的重载。

1 int add(int a,int b);             //函数1
2 int add(int a,int b,int c);       //函数2

C语言中,如果你定义了函数1,那么就不能再定义函数2.不然编译就不通过了。究其原因,可能是因为C语言中有函数指针这东西(见一下代码段,重载会让C编译器不知道将哪个函数地址赋给函数指针)。

#include <stdio.h>
int add(int a,int b);
//int add(int a , int b , int c);
int sub(int a,int b);
void result(int (* pf)() , int a , int b);
main(){
   int i,j=1;
   int (* pf)();
   pf=add;        //这里如果重载了add函数,那么这里编译器就不知道要把哪个add
   result(pf,i,j);//赋值给pf
   pf=sub;
   result(pf,i,j);
}

int add(int a , int b){
     return a+b;
}
int sub(int a,int b){
     return a-b;
}
void result(int (*pf)() , int a , int b){
   int value;
   value = (*pf)(a , b);
   printf("%d\t",value);
}

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110120.html原文链接:https://javaforall.net

(0)
上一篇 2021年8月24日 上午8:00
下一篇 2021年8月24日 上午8:00


相关推荐

  • hdfs常用操作命令

    hdfs常用操作命令hdfs常用操作命令

    2022年4月23日
    42
  • memset()函数及其作用

    memset()函数及其作用1 memset 函数原型是 externvoid memset void buffer intc intcount nbsp nbsp nbsp nbsp nbsp nbsp buffer 为指针或是数组 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp c 是赋给 buffer 的值 nbsp nbsp nbsp nbsp nbsp nbsp count 是 buffer 的长度 nbsp nbsp nbsp nbsp nbsp nbsp 这个函数在 socket 中多用于清空数组 如 原型是 memset buffer 0

    2026年3月19日
    3
  • oracle命令创建新用户

    oracle命令创建新用户一、sqlplus连接oracle1、sqlplus登录Windows需要sqlplus命令框,获取CMD窗口下输入sqlplus(需要先安装成功oracle)2、输入用户名和口令(密码)3、以sysdba身份连接oracleconnsys/密码assysdba4、查看当前查看当前实例名selectinstance_namefr…

    2022年5月19日
    60
  • Google earthios_初步探索的重要成果

    Google earthios_初步探索的重要成果一、申请使用1.GoogleEarthStudio(以下简称GES)需要申请才能使用,前往GoogleEarthStudio官网注册申请,审核时间较久.2.审核通过,填写信息时留下的邮箱会收到如下提醒3.在Chrome浏览器中打开网址https://earth.google.com/studio/,会看到如下截图二、启动页1.新建项目,有两种方式分别是Blan…

    2026年1月22日
    5
  • win10eplan激活码破解步骤【中文破解版】

    (win10eplan激活码破解步骤)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月22日
    208
  • tf卡锁定怎么解锁_tf卡写保护解除办法

    tf卡锁定怎么解锁_tf卡写保护解除办法最近这段时间,开始使用TFS2010进行项目的源码管理,在使用过程中,发现了不些问题,由于开发人员的操作失误,经常导致了源码中的文件被锁定,而在开发人员的PC机上又不能把锁定的文件签入到TFS中,刚开始遇到这个问题时,想通过管理员帐号来“取消锁定”,但在“源代码管理器”中,管理员帐号也没有权限操作“取消锁定”。遇到这种文件被锁定的事,是相当的郁闷。郁闷归郁闷,问题还是得要解决,…

    2026年2月21日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号