硬件
★只有在乘除里才用上B,平时可以当B是一般寄存器使用
★EA启用外部ROM,当EA=1使用内部ROM,当EA=0使用外部ROM。8031/8032没有内部ROM所以EA接地 ★ALE=1时P0是地址, ALE=O时P0是数据
★PSEN程序ROM启用信号,接到外部ROM的使能端OE; 而WR,RD则访问外部RAM的控制信号。 ★坏掉的8x51,8x52很可能是内部ROM坏掉了,可以将EA引脚接地,改外接ROM,即当8031/8032使用 ★片内RAM组成: 128B 128B(可直接寻址) 寄存器组0 寄存器组1 寄存器组2 寄存器组3 可位寻址区 一般数据\\堆栈区 特殊功能寄存器SFR 00H~07H 08H~0FH 10H~17H 18H~1FH 20H~2FH 30H~7FH 80H~FFH R0~R7 R0~R7 R0~R7 R0~R7 128B 128位 80B(80字) RS1RS0=00 RS1RS0=01 RS1RS0=10 RS1RS0=11 SETB 25H.2 复位SP=7,与寄存器 =SETB 42 冲突,MOV SP,#30H ★只有P0口没有上拉电阻 ★每个I/O想输入必先输出1
★LED发光管,1:1.7v压降;2:10~20mA电流。 因为单片机驱动能力(电流)有限,所以应外部供电,外vcc流入,再加电阻 ★继电器:a-b-c只有一组就成1p.
★[注]:驱动带电感的负载应反接个二极管(并联),以放电保护 ★ 驱动继电器(大负载)用继承反相器(7405[5v],7406[12v]) 蜂鸣器用两个小的三极管组成 达林顿 驱动 LED发光管,加限流电阻或反相器 ★跳线也是开关
★凡是输入设备,加个上拉电阻会大大加强1的输入能力 ★按钮使用在边缘触发, 闸刀开关使用在电平触发
★对于TTL,输入引脚悬空相当于H,为不受干扰,不用的引脚尽量不悬空 ★异步通信:发送和接收社别使用各自的时钟(要求大家的时钟尽可能一致)
★数码管是八个引脚对应abcdegh dp 八个段,浪费io口,为了节省,和不用查编码表,通常还加个BCD7段译码器 共阳有:74LS48,74LS49,CD4511 共阴用:74LS46,74LS47,CD4513 如果不加译码器,那么就是通过IO口驱动,为了增强驱动能力,就加锁存器373, 同步通信:
★★★★★ IIC总线协议 ★★★★★
一、I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。(既:时钟高电平时是数据传送,不允许数据变化。时钟低电平时数据才可以改变)
二、起始和终止信号
起始信号:SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号; 终止信号:SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。(因为传输状态:时钟为高时,数据保持恒定)
★处理速度比较慢的接收器件收到一个完整的数据字节后,将SCL线拉成低电平,从而使主机处于等待状态。直到接收器件准备好接收下一个字节时,再释放SCL线使之为高电平,从而使数据传送可以继续进行。
★★★★★ DS18B20测温 ★★★★★
写1写0在于对器件电平拉低时间的控制:单片机拉低15~60 u秒就是写0,拉低1~15u秒再放开就是写1
软件
★数据类型 类型 符号 整型 有 关键字 所占位数 数的表示范围 (signed)int 16 -32768~32768 (signed)short 16 -32768~32768 (signed)long 32 -21474838-21474838 Unsigned int 16 0~65535 无 Unsigned short int 16 0~65535 Unsigned long int 32 0~4294967295 Float 32 实型 有 Double 有 Char 8 -128~127 无符型 有 Unsigned char 8 0~255 无 【注】强制类型变换,char I; int j=0xABCD; 若i=j; 则i只得到j的低8位,既I = = CD;
★C语言运算符又13类 算术运算+-*/% 关系运算> < == >= <= != 逻辑运算 ! && || 位运算 >> << ~ | ^ & 赋值 = 条件运算 ? : 逗号运算(数组中用到), 指针运算 *取值 &取地址 求字节数 sizeof 强制类型转换 () 分量运算 结构体用到 . -> 小标运算[ ] 函数调用运算符 () I++ i-- ++I --I I=3 ;J=i++; (j=3,i=4) j=++I;(j=4,i=4) ★Switch case 语句比else if,,,else if更方便,而且不是更方便问题,他不会再逐项检查各个条件,而是只要一个条件真了,就不检查其他条件了,节省了中断中的时间(在中断中特别需要简洁,否则一定会影响主程序的执行) Switch(x){ Case 1: {Y=’a’;break; }//一定要有break, Case 2: {Y=’b’;break; } ……………… Default: {Y=’o’;break;} }
★也不要忘记 do{。。。}while();使用
★可以用break;跳出循环体;for(…….){… if()break;….}
★Continue:忽略本次,继续执行下一次循环,for(….){… if(i==5) Continue;….}就是不执行i=5这一次;只会错过i=5这次; ★宏定义#define LED_ON 0xff (不需要分号) #define led_enable() LED=1 (这样,以后在函数中led_enable();就相当于LED=1;不要以为是调用了函数) 反正宏定义就是 字符的代替,以后在函数中只要出现定义好的字符串就相当于写了所代替的 进去 ★带参数的宏定义:#define sib(x,y) x = y +2 这样宏定义以后,之后出现了sib(P0,6); 就相当于写了式子:P0=6+2;
★记得随时利用java的面向对象思想:每个动作都交给对象去多,不要都在main里全包
★先定义所有的函数再使用,否则不能调用出现在后面的函数 ★之所以要定义数据类型,就是要为变量预留空间
★MCU是8位的,而数据类型只有char/unsigned char 是8位,所以这两类型I/O等控制。比int常用
★bit是定义0x20~0x 2F的位,sbit定义SFR(特殊功能寄存器)eg:char bdata scan; sbit i=scan^2; i是scan^2第三位 ★sfr定义SFR,eg:sfr P0=0x80; 这些程序都在头文件里包含,所以很少会在自己的程序里出现 ★sfr16定义内部RAM 16位的SFR,sfr16 DPTR=0x82; ★ unsigned int a;//记得要分号 #define uint unsigned int//不要分号 ★定义时:变量与函数也不能同名. C语言跟java不象
★c语言没有movc,movx等访问语句,c是通过定义数据的 存储器形式 来实现的 code Char code table[]={0x03,0x07,0xfe,.....} 程序存储器(表格) ROM的K data Char data x ; 直接寻址内部RAM RAM前128B idata Char idata x ; 间接寻址内部RAM RAM第二128B bdata 位寻址 20H~2FH 128位 Bit bdata x ; xdata KB Char xdata x; MOVX 以DPTR寻址的外部RAM pdata 一R0、R1寻址的内RAM 256B内8052才有 Char pdata x; R0、R1可寻址到的 ★&& 和 & 区别,X&&Y事件“与”:X、Y事件同时成立;X&Y位“与”: X、Y每个位相与。|| | ! ~道理相同,^异或 记法:“单位”
★某位置1,就是该位|1; 某位置0,就是该位&0; 某位取反,就是该位^1 ★c语言的真假用1、0表示而不用true、foat ★++ -- 很有效
★numwe=(numwe==5)?0:numwe+1;//靠!不能用numwe++而要numwe+1,否则它没有赋值给numwe ★D%=X; D=D%X; *= &= ....道理相同 ★数组:声明字符用“”,其余用{};char table[]=”hello”; int table[]={20,3,43,1} ★数组:a[行][列] int num[3][2]={{1,2},{3,4},{5,6}} ★几个死循环(等待中断) for(;;); while(1);
★中断子程序:1不输入,不输出; 2不需先声明; void timer() interrupt 1 using 2 (不用R0,主程序用了) ★12Mhz时钟工作下,for(i=0; i<600; i++); 执行一个这样600循环延时是5ms
★12Mhz时钟工作下,一个定时器常数单位耗时1μs,所以填5000常数延时5ms,1000延时1 ms
★人的视觉在60hz下不觉得闪烁,即延时1/60=16ms (频率越低就越亮,所以这个60hz是人视觉不觉得闪烁的最低频率) 如要扫描8个数码管使个觉得闪烁,即每个数码管定时2ms ★按键延时抖动和整个按键处理(按键抖动10~20ms) If(pb1= =0){ delay(20ms); while(pb1= =0);//等待松手 service();} //三步:1去抖动2等松手3服务 ★简单的取代-crol-方法(1):LED=(LED<<1)|0x01; //注意:c语言没有循环左移右移方法,想有就#include第三方进来 ★取代-crol-方法(2):LED= ~ (~ LED<<1)
★if-else if 带优先级, switch – case() 不带优先级
★ P0=table[bai]; //要把习惯改了:要先送数再 段选、位选,否则之前P0口的数会影响一个指令时间(执行dula=1;时)
dula=1; dula=0; ★uchar keyscan(){ //扫描键盘是高位输入,低位输出 char i; P3=0xfe; //1111 1110 for(i=0;i<4;i++){ //移位4次就可以扫描全部 temp=P3; temp = temp&0xf0; //屏蔽低位(就是把输出屏蔽,看0有没有从高位输入进来) if(temp!=0xf0){ //如果 delay(4); //消除抖动 temp=P3; temp = temp&0xf0; if(temp!=0xf0) // 消除抖动后还是否按下 temp = P3; break; //这个break是跳出for,而不是if } P3 = (P3<<1)|0x01; //移位机器自动补0,所以要在后面加1(取代了移位函数) }
return temp; //返回键码 }
★两种方法实现6个数码管 “跑马灯”效果,现在只推荐下面这方法(很灵活,很容易改成不同效果) #include #define uchar unsigned char uchar code du_table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x0}; uchar code we_table[]={ 0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; char disp_paomadeng[6][6]={//跑马灯效果 {8,0,5,1,16,16},{0,5,1,16,16,8},{5,1,16,16,8,0},{1,16,16,8,0,5},{16,16,8,0,5,1},{16,8,0,5,1,16} };//16表示无显示, 这个方法很妙,可以这样达到 飞入 , 跑马灯 等效果 char code disp_feiru[18][6]={//飞入效果 {16,16,16,16,16,8},{16,16,16,16,8,16},{16,16,16,8,16,16},{16,16,8,16,16,16},{16,8,16,16,16,16},{8,16,16,16,16,16}, {8,16,16,16,16,0},{8,16,16,16,0,16},{8,16,16,0,16,16},{8,16,0,16,16,16},{8,0,16,16,16,16}, {8,0,16,16,16,5},{8,0,16,16,5,16},{8,0,16,5,16,16},{8,0,5,16,16,16}, {8,0,5,16,16,1},{8,0,5,16,1,16},{8,0,5,1,16,16} }; sbit dula=P2^6; sbit wela=P2^7; void delay(int x){ int i,j; for(i=0;i void main(){ int i; while(1){ for(i=0;i<18;i++){ display(i);//传入i表示要显示第i行 } for(i=17;i>-1;i--){//要注意传入的行数越界,所以i由17开始,到0结束(i>-1) display(i);//传入i表示要显示第i行 } } } ★中断小结:[注]加了*表示不可以位寻址 2:即使没设定中断允许标志位也会变化,只是这是想知道他变化要用程序不断查询它,不能自动跳到中断服务程序去 中断源 设置 例程:0:INT0 1:T0 2:INT1 3:T1 4:TXD/RXD INT0/INT1 1中断允许IE:EA(总允许), EX0 / EX1(中断开关), Main(){ IE=1; EX1=1; IT1=0; } 2 TCON:IT0 / IT1(触发方式:1弦,0平), IE0/IE1(中断标志) Void my_int1(void) interrupt 2 using 2{中断服务} (中断程序特征:空I/O, interrupt x中断向量) 3优先级别IP:PX0 / PX1 (缺省,在需要区分优先才设置) T0 / T1 int i=0; 1中断允许IE:EA(总允许), ET0 / ET1(中断开关), char line=0xfe; 2 TCON:TR0/TR1(启动开关),TF0/TF1(中断标志) void main(){ 3 TMOD: 高T1低T0:GATE|C/T|M1|M0|GATE|C/T|M1|M0 EA=1; GATE=1外部启动,需要TRx=1,同时INTx=1才能启动Tx ET0=1; C/T=1:定时器; C/T=0:计数器 TMOD=0x01; M1 M0:决定工作方式:0(13位),1(16位),2(自动加载),3(无需) TR0=1; 5 MODE0: TL0=(8192-x)%32 // 32=2 ,取5位的余数 TH0=(65536-50000)/256; 5 TL0=(65536-50000)%256; TH0=(8192-x)/32 // 32=2 ,取5位的商 8while(1); MODE1: TL0=(65536-x)%256 // 256=2 ,取8位的余数 } TH0=(65536-x)/256 // 256=28 ,取8位的商 void my_t0() interrupt 1{ MODE2: TL0=256-x // 填入计数值 TH0=(65536-50000)/256; TH0=256-x // 填入自动加载值 TL0=(65536-50000)%256; MODE3:不用理会他,很多余 if(++i==5){ 4优先级别IP:PT0 / PT1 i=0; 经验:12MHz每单位计数一次定时1μs line=~(~line<<1); P1=line; } } TxD / RxD 1中断允许IE:EA(总允许), ES(输入输出公用一个中断开关) 具体步骤如下: 2 SCON:SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI 1:确定T1的工作方式(编程TMOD寄存器); SM0、SM1确定工作模式: 2:计算T1的初值,装载TH1、TL1; MODE0:1:以固定比特率OSC/12, 3:启动T1(编程TCON中的TR1位); 2:不管接收、发送数据都接RxD,脉冲接TxD 4:确定串行口控制(编程SCON寄存器); 3:每桢8位(不含起始,停止位) 5:串行口在中断方式工作时,要进行中断设 MODE1: 1:以Timer1来控制比特率(通常Timer1的mode2) 置(编程IE、IP寄存器)。 void main() (只学这个2:RxD接对方TxD,TxD接对方RxD { TMOD=0x20; //步骤1 T1工作方式 3:每桢9位(起始+8数据+停止) TH1=0xfd; //步骤2 T1的初值 MODE2: 1:以固定比特率OSC/32,OSC/ TL1=0xfd; //比特率为92000xfd 2:同MODE 1 TR1=1; //步骤3启动T1 3:每桢9位(起始+8数据+奇偶[TB8]+停止) REN=1; //步骤4 串行口控制 MODE3 除以Timer1控制比特率,其余与MODE2一样 SM0=0; SM1=1; REN:接收启动位 EA=1; //步骤5 中断设置 T1:传送中断(手工清零) ES=1; R1:接收中断(手工清零) while(1); 3 SMOD(位) :用于比特率倍增 } MODE2: 比特率= fosc·(2SMOD/) void ser() interrupt 4 //中断服务程序 MODE1、3: 比特率=fosc ·2SMOD/[384.(256-TH1)] { RI=0; //一定要手工清零标志位 4(Timer1设置):TMOD、TH1、TL1、TR1(启动) P1=SBUF; //串口输入(就这么简单) } ★写一个程序 : 串口输入什么就马上从串口输出什么 (演示了串口的自动进入中断服务和查询进入服务的) #include { TMOD=0x20; TH1=0xfd; TL1=0xfd; TR1=1; REN=1; SM0=0; SM1=1; EA=1; ES=1; while(1) { if(flag==1) { 查询进入服务 使用的是 发送串口 ES=0; //先关中断,否则后面发送完后会自动进入中断程序,这样就进入死循环 flag=0; SBUF=a; while(!TI); //等待发送完毕 TI=0; //这里是清空发送标志TI ,而中断服务程序里清空的是接受标志RI ES=1; // } } } 自动进入中断服务使用的是 接收串口 void ser() interrupt 4 { RI=0; P1=SBUF; a=SBUF; flag=1; } ★检测键盘时,要松手才进行动作,不要消除抖动好就马上动作 JB KEY2,KEYL3 LCALL DELAY JB KEY2,KEYL3 JNB KEY2,$;等待松手后才执行函数 LCALL FTION3; ★ BCD转16进制 MOV B,#16 DIV AB MOV DATA_TEMP,A MOV ADD_TEMP,B MOV B,#10 MUL AB ADD A,ADD_TEMP ★ 16进制转BCD MOV A,SHI MOV B,#10 DIV AB MOV DATA_TEMP,A MOV ADD_TEMP,B MOV B,#16 MUL AB ADD A,ADD_TEMP ★★★★★★★★★★★★★★★★ 模块化编程 ★ ★★★★★★★★★★★★★★★★★★★ 不是将所有的函数都放到一个c文件里 模块化编程原则:高内聚 ——在一个C文件里面的函数只有相互调用,而没有调用其他文件的函数(不会交叉引用) ——模块之间的接口尽量少、和简单 模块化编程的步骤: 第一步:创建头文件 创建一个.C文件(源文件)和一个.h文件(头文件)。原则上.C文件和.h文件同名; 文件名要有意义,最好能体现该文件代码功能。如:delay.c与delay.h 第二步:防重复包含处理 在.h文件中加入如下代码:(只是防止重复包含,不写这段代码也是可以的,只要自己不重复包含) #ifndef xxx #define xxxx ……… #endif 在同一个工程中各个.h文件xxxx不能相同,因此使用一下规则: 将.h文件的文件名字全部大写,“.”替换成下划线“_”,首尾各添加2个下划线“_” 例如:delay.h #ifndef_ _DELAY_H_ _ #define_ _DELAY_H_ _ ………. #endif 第三步:代码封装 将需要模块化的代码封装成函数与宏定义。 需要被外部调用的宏定义放在.h文件中,仅会被本.c文件调用的宏定义放在.c文件中。 尽量不用全局变量(因为减少模块间的关联),必须要用的全局变量的声明放在.c文件,当需要调用外部全局变量需要在.h文件中用extern重新声明一下。 第四步:使用源文件 将.c文件添加到工程之中,同时:在需要调用.h文件中的宏或者函数的.c文件中添加代码将该.h文件包含进去。 所包含的头文件中的函数,宏定义,全局变量可以在.c文件中自由调用。 例如:#include<51.h>里面就包含了p口的定义,所以用起来就这么方便了,只要P2^4….就会知道第几口 电机每圈4000ns =4ms 既是每秒250圈 266.3 PROTEL ★常用快捷键 鼠标拖着元件+X,X方向镜像翻转 鼠标拖着元件+Y,Y方向镜像翻转 删除元件E+D PCB中找元件J+C Q转换单位 *手工画线时,可以切换图层,会自动放置过孔,很好用
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- baoaiwan.cn 版权所有 赣ICP备2024042794号-3
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务