找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3464|回复: 5
收起左侧

代码研究所之单片机

[复制链接]
ID:71477 发表于 2015-1-2 00:01 | 显示全部楼层 |阅读模式
本帖最后由 shaonv 于 2015-1-2 00:02 编辑

接触单片机起初也要追溯到大二了,书本上学的也都是汇编或者高级汇编,对汇编我就知道两个字无语;接触C应该是在大一吧,纯粹是为了应付考试,却不幸挂科了,之后我不再接触……
    研究生一年级开学之初迫于老李淫威继续C继续单片机继续代码……
    结合C+单片机一起来分析,学习单片机就要简单多了:
    首先要养成一个好习惯,写函数时比如 main(),为了函数的健壮性和美观性可这样写:
void main(void),第一个void表示无返回值,第二个void表示无参数。定义变量和函数名时尽量使用中文对应英文的简写或全称,例如:定义一个长度的变量:unsigned char Length;若定义常量则使用以下语句:#define  Length  8    此语句后面不要添加分号。
    在编程的时候要注意变量值域,这是新手经常遇到的问题,多见于延时函数,例如:
    void delay(void)
    {
        unsigned char i,j;
        for(i=0;i<=30;i++)
            {
              for(j=0;j<=256;j++);  
           }
    }
    程序编译无警告无错误,但程序运行会死掉,为什么?因为j是unsigned char 型值域为0~255,而函数中的j值超出此值,导致系统崩盘。不要小看这点错误,也许就是这个简单的问题导致你的系统运行死掉。
    到这里你有没有发现每次都要写unsigned char会很麻烦呢?所以要选择一种替代方式,如下:
    #define unsigned char u8
    #define unsigned int  u16
    #define unsigned long u32
    在ARM一般采用以下方式:
    typedef unsigned char u8;
    typedef unsigned  int  u16;
    typedef unsigned long u32;
    注意以上两种方式效果是一样的,写法区别还要看清楚前面和后面的符号。
    简单的讲述了以上基本编写单片机程序的主意事项,下面我们来看一个简单的LED灯程序:
    #include "reg51.h"
    #define unsigned char u8
    #define unsigned int  u16
    #define unsigned long u32
    sbit LED=P0^0;//p0.0为LED口
    void delay(void)
    {
        u8 i,j;
        for(i=0;i<=220;i++)
            {
              for(j=0;j<255;j++);  
           }
    }
    void main(void)
    {
        while(1)
        {
            LED=0;//亮
            delay(); //延时达到闪烁效果
            LED=1;//灭
        }
    }
    以上便实现了简单的使用51单片机点亮一个LED灯,当然实现流水灯的方法也是水到渠成的,程序如下:
    #include "reg51.h"
    #define unsigned char u8
    #define unsigned int  u16
    #define unsigned long u32
    #define  LedPort   P0        //为LED口
    u8 code table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff};//p0.0-p.07顺序亮,最后全灭
    void delay(void)
    {
        u8 i,j;
        for(i=0;i<=220;i++)
            {
              for(j=0;j<255;j++);  
           }
    }
    void main(void)
    {
        u8 num;
        while(1)
        {
           for(num=0;num<9;num++)
            {
                LedPort=table[ i];
                delay();
            } 
        }
    }
    以上程序便能实现简单的流水灯,如果想要不同的花样可在延时时间和流水灯走灯路线上更改。
    为了便于程序的可移植性,一般都采用替代方式声明,此程序中是采用P0口作为LED灯的输出口,所以用了以下语句来增加程序的可移植性:#define  LedPort   P0        //为LED口
    在学习单片机C编程时要重细节,粗看框架,多看书,勤编写,对不同版本相同功能的程序分析各自的优缺点,取长补短,学习其长处。
    以上便是我对入门单片机的程序编写的一个简单的概述,有不同意见或不同看法者,请留言探讨,谢谢!
回复

使用道具 举报

ID:71477 发表于 2015-1-2 00:02 | 显示全部楼层
接上代码研究所之单片机(1),本次主要针对一些编写代码时所要注意的和单片机C编程的基础知识。
一:数据类型·运算符·表达式
1.1        C51支持的数据类型
数据类型
名称
长度
值域
基本类型
bit
1 bit
0,1
Unsigned charchar
1 byte
0~255-128~127
Unsigned intint
2byte
0~65525-32768~32767
Unsigned longlong
4 byte
0~4294967295
Float
4 byte
6位数字
Double
8 byte
10位数字
构造类型
数组
结构体
共用体
枚举
指针类型
2~3byte
存储空间,最大64KB
空类型
1.2        常量和变量
常量:#define CONST 10 变量:bit  b_start //位变量 Char      c_start//字符变量 其他略。
1.3        C51存储器·寄存器定义 定义:分为片内数据存储器·片外数据存储器·片内程序存储器·片外程序存储器。 1.31     C51的数据存储类型
关键字
存储器对应关系
data
直接寻址片外数据存储器(128byte
bdat
片内位寻址存储空间(16byte
idata
间接寻址片内数据存储空间,可以访问RAM全部内容
pdata
分页寻址片外数据存储器(256byte
Xdata
片外数据存储器(64KB
Code
代码存储器(64KB
例子:char data c_Var; //无符号char型变量,定义到内部存储空间低128byte
1.32     寄存器 Sfr SBUF=0x99;         //定义串行数据寄存器 Sfr16    T2=0xcc    //定义T2计时器数据存储器
Sbit D0=P2^1;定义位变量 Sbit      CY=0xd7;使用绝对地址定义
使用sbit定义变量空间 Bdata unsigned char uc_shield_byte; Sbit     b_x= uc_shield_byte^1;           //定义首位 Sbit     b_y= uc_shield_byte^2; Sbit b_z=uc_shield_byte^3;
1.4        逻辑运算 与:    &&         或:||      非: ! 位逻辑运算 位与:& 位或|  位异或:   ^ 位取反:      ~
1.5        移位运算 左移位:<<,个位左移,补0; 右移位:>>,高位右移,补0
回复

使用道具 举报

ID:71477 发表于 2015-1-2 00:03 | 显示全部楼层
二:C51控制流
1)              顺序结构
2)              选择结构
1.         If……else语句
2.         If语句
3.         Switch语句
Switch(判断条件)
{
Case 常量表达式1{语句块1}break
……
Default{语句n+1}break
}
4.         Ifswitch嵌套
3)              循环结构
1.         While语句
2.         Do while语句
Do{
代码块;
}while(条件);
3.         For语句
三:函数
1.无参数函数定义
Void 函数名(void//无参数,无返回值函数定义
{ }
Int 函数名(char achar b//带参数,带返回值函数定义
{ }
2.局部变量和全局变量 静态局部变量和动态局部变量
Static      int       a;静态(static不可省略) Auto        int         a;动态(auto可省略)
3.   内部函数和外部函数
1)内部函数:static unsigned char  Funint a); 内部函数只能被该源文件中的其他函数调用
2)外部函数:extern unsigned char Funint a); 外部函数可以被其他源文件调用的函数

四:数组和指针
1)   数组:
l  一维数组: 类型      数组名【size;
l  二维数组 类型      数组名【size A】【size B】;
l  字符数组
Char ch1【】={‘j’,’a’,’c’,’k’,’x’,’u’};以字符形式赋值
Char ch1[]={“jackxu”};              以字符串形式赋值
2)   指针 1)         指针和指针变量  类型    *变量名 Int *ptr1float *ptr2char *ptr3
2)         指针的引用 Int  a=10Int  *p=&aX=a ;直接访问方式 X=*p;间接访问方式
3)   数组和指针 Int a[]={1,2,3,4,5,6,7,8,9,10}*ipIp=a //*ip代表a[0],*(ip+i)代表a[ i];
二维数组与指针同上;
4)   字符串和指针 不能用指针变量来修改字符串常量;
5)   数组,指针和函数的关系
回复

使用道具 举报

ID:71477 发表于 2015-1-2 00:04 | 显示全部楼层
1)数组可作为函数的参数:int sum(int  a[],int num); 2指针作为函数参数:int sum(int  *ip,int num); 3)返回指针的函数:char *ip(char *ip,char c);

(6)   指针数组和指向指针的指针

1)类型 *数组名【size】; Char *name【3】={“I”,“love”,“you”};定义了三个字符型指针数组并进行了初始化 3)         类型  **指针变量名  //指针变量的变量声明 *指针变量      //获取指针变量指向的指针 **指针变量     //获取指针变量指向的指针内容

例子: Main() { Char *name[]={“Tom”,”Jacky”,”Andy”}; Char **cp=name; For(int i=0;i<3;i++) {  Printf(“cp=d%\n”,cp);  Printf(“*cp=s%\n”,*cp); Printf(“**cp=c%\n”,**cp); } } 程序输出结果为:cp=0x1000; *cp=Tom; **cp=T ;Cp=0x1002 ;*cp=Jacky; **cp=J ;cp=0x1004; *cp=Andy ;**cp=A
回复

使用道具 举报

ID:71477 发表于 2015-1-2 00:04 | 显示全部楼层
五:结构,联合和枚举

定义:  1) Stuct 结构名

{ 类型说明符 成员1   类型说明符 成员2   。。。。。。  类型说明符 成员n

}; 结构名  变量名1,变量名2…….;

2) Stuct 结构名 { 类型说明符 成员1 类型说明符 成员2  。。。。。。 类型说明符 成员n }变量名1,变量名2…….;

3) Stuct {类型说明符 成员1 类型说明符 成员2 。。。。。。 类型说明符 成员n }变量名1,变量名2…….;

例子: Struct date {Unsigned char      Year; Unsigned char   Month; Unsigned char   Day; Unsigned char    Hour;

}; Struct date  ERR_TIME【20】;

//初始化 ERR_TIME【0】.Year=99; ERR_TIME【0】.Month=8; ERR_TIME【0】.Day=23;

ERR_TIME【0】.Hour=22;

(1)指向结构体变量的指针 Struct 结构体名 *指针变量名 Struct date *p_Date; P_Date=&ERR_TIME; (*p_Date).Year=99;P_Date->Month=8;

例子:求平均数 Struct member { Float Slaray; }flashman【5】={{3000},{4000},{5000},{6000},{7000}};

Float AVRage(struct member *p_Man) { Float avr,sum;Unsigned char  j;  Sum=avr=0; For(j=0;j<5;j++)  {Sum=sum+p_Man->Slaray;  If(j=4) { Avr=sum/5; } } Return avr; } Main() {  Float avr; Struct member *p; P=flashman; Menberavr=average(p); }
回复

使用道具 举报

ID:71477 发表于 2015-1-2 00:05 | 显示全部楼层
本帖最后由 shaonv 于 2015-1-2 00:06 编辑



(2) 联合体;定义: union 结构名 { 类型说明符 成员1 类型说明符 成员2  。。。。。。 类型说明符 成员n





}; 结构名  变量名1,变量名2…….;



2) union结构名 { 类型说明符 成员1  类型说明符 成员2  。。。。。。类型说明符 成员n }变量名1,变量名



2…….;



3) union {  类型说明符 成员1 类型说明符 成员2 。。。。。。 类型说明符 成员n }变量名1,变量名2…….;



(3) 枚举 1)定义:Enum 枚举名 { 枚举值列表; };枚举名 变量1,变量2,……;



  2) Enum 枚举名 {  枚举值列表; } 枚举名变量1,变量2,……;



六:程序设计技巧 中断响应快速的一种解决方法



  #define N 256    Char data[N] Static int couter=0; Void main(void) {If(flag==1){ Handledata(dat



a);       //数据处理模块 } }



Void Timer0 (void) inteerupt 1 { Data[counter]=AD_result; If(couter++>=N) {Flag=1; Counter=0; } }



总结:将中断采集到的数据处理模块移到主程序中操作,节约了中断函数执行时间,使得程序能快速响应中断并使得程序不会因处理模块运行时间超过了中断时间而出错; 下一期我将会特别讲述中断及编程方法,中断,中断函数,中断标志之间的关系及注意事项。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表