keil c51默认并无携带STC芯片的固件库,添加固件库的步骤以下:html
一、在下载软件右侧tab界面选择“keil仿真设置”标签,并点击下方红框框出的按钮(“添加型号和头文件…到Keil中”按钮)进行添加。如图1所示。
二、选择添加固件库的路径,如图2所示。务必注意要选择Keil软件的安装根目录,选择好以后点击“肯定”。
当咱们再打开keil软件新建工程时,就能够看到咱们所须要的芯片型号了。如图3所示。
web
#include “reg52.h” sfr P4 = 0xc0; // reg52.h 中没有定义 P4 寄存器故本身定义 sbit P3_6 = P4^2; // 位定义用 P3_6 在程序中替换 P4^2的功能 sbit P3_7 = P4^4; // 同上
#include “stc15f2k60s2.h” // 该文件已定义 P4 寄存器故无需重复定义 sbit P3_6 = P4^2; // 位定义用 P3_6 在程序中替换 P4^2 的功能 sbit P3_7 = P4^4; // 同上
// 经过译码器选择对应的锁存器 void select(uchar num) { switch (num) { case 4: P2 = (P2 & 0x1f) | 0x80; break; case 5: P2 = (P2 & 0x1f) | 0xa0; break; case 6: P2 = (P2 & 0x1f) | 0xc0; break; case 7: P2 = (P2 & 0x1f) | 0xe0; break; default: P2 &= 0x1f; break; } } void init() { // 关闭蜂鸣器、LED灯、数码管 select(5); // 关闭蜂鸣器 P0 = 0x00; select(4); // 关闭LED灯 P0 = 0xff; select(6); // 选中所有数码管 P0 = 0xff; select(7); // 关闭数码管 P0 = 0xff; select(0); // 锁存 }
// Delayms void delayms(uint time) { uint i, j; for (i = time; i > 0; i--) for (j = 845; j > 0; j--); }
uchar numChar[] = {0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8, 0X80, 0X90}; // 数码管 void shumaguan(uchar wei, uchar num) { select(7); // 关闭数码管 P0 = 0xff; select(0); P0 = 0x00; select(6); // 位选 P0 = 0x80 >> wei; // [0x80]从左至右 [0x01] 从右至左 select(0); P0 = 0xff; select(7); P0 = numChar[num]; select(0); Delay3ms(); // 延时 3ms }
void Timer0Init(void) // 10 毫秒 @11.0592MHz { AUXR &= 0x7F; // 定时器时钟 12T 模式 TMOD &= 0xF0; // 设置定时器模式 TL0 = 0x00; // 设置定时初值 TH0 = 0xDC; // 设置定时初值 TF0 = 0; // 清除 TF0 标志 TR0 = 1; // 定时器 0 开始计时 EA = 1; ET0 = 1; }
void Timer1Init(void) // 10 毫秒 @11.0592MHz { AUXR &= 0xBF; // 定时器时钟 12T 模式 TMOD &= 0x0F; // 设置定时器模式 TL1 = 0x00; // 设置定时初值 TH1 = 0xDC; // 设置定时初值 TF1 = 0; // 清除 TF1 标志 TR1 = 1; // 定时器 1 开始计时 EA = 1; ET1 = 1; }
void Timer2Init(void) // 10 毫秒 @11.0592MHz { AUXR &= 0xFB; // 定时器时钟 12T 模式 T2L = 0x00; // 设置定时初值 T2H = 0xDC; // 设置定时初值 AUXR |= 0x10; // 定时器 2 开始计时 EA = 1; IE2 |= 0x04; }
void initInter0() { IT0 = 1; // 中断触发方式:[0]低电平触发 [1]下沿触发 EX0 = 1; // 打开外部中断 EA = 1; // 开启总中断 }
void initInter1() { IT1 = 1; // 中断触发方式:[0]低电平触发 [1]下沿触发 EX1 = 1; // 打开外部中断 EA = 1; // 开启总中断 }
注:koa
1 | ~ | 4 |
~ | … | ~ |
11 | ~ | 16 |
// 矩阵键盘 // IAP15 芯片的 WR/RD 功能不是 P36/P37 引脚功能,故用 P42/P44 引脚代替 // 即:P3^6 => P42 P3^7 => P44 uchar keyScan() { uchar keyValue = 0; // 键盘初始化 P3 = 0x0f; P42 = 0; P44 = 0; // 键盘扫描 if (P3 != 0x0f) { delayms(10); // 消抖 if (P3 != 0x0f) { switch (P3) { case 0x07: keyValue = 13;break; case 0x0b: keyValue = 9; break; case 0x0d: keyValue = 5; break; case 0x0e: keyValue = 1; break; default: return 0; } // 键盘翻转 P3 = 0xf0; P42 = 1; P44 = 1; // 扫描 if (!P34) keyValue += 3; else if (!P35) keyValue += 2; else if (!P42) keyValue += 1; else if (!P44) keyValue += 0; else return 0; // 等待按键抬起 while (P3 != 0xf0); while (!P42); while (!P44); } } return keyValue; // 返回按键值,如无按键按下则返回 0 }
注:svg
// EEPROM 设备地址 0xA0 void writeByte(uchar addr, uchar byt) { IIC_Start(); IIC_SendByte(devAddr); IIC_WaitAck(); IIC_SendByte(addr); IIC_WaitAck(); IIC_SendByte(byt); IIC_WaitAck(); IIC_Stop(); } uchar readByte(uchar addr) { uchar dat; IIC_Start(); IIC_SendByte(devAddr); IIC_WaitAck(); IIC_SendByte(addr); IIC_WaitAck(); IIC_Start(); IIC_SendByte(devAddr | 0x01); IIC_WaitAck(); dat = IIC_RecByte(); IIC_Ack(0); IIC_Stop(); return dat; }
// AT24C02 共 256 个字节 分为 8 页 共 32 页 // 页写入 void write(uchar addr, uchar len, uchar *arr) { while (len > 0) { while (1) { IIC_Start(); IIC_SendByte(devAddr); if (IIC_WaitAck()) break; } IIC_SendByte(addr); IIC_WaitAck(); while (len > 0) { IIC_SendByte(*arr++); IIC_WaitAck(); len--; addr++; // 判断是否达到页边界 if ((addr & 0x07) == 0) break; } IIC_Stop(); } } void read(uchar addr, uchar len, uchar *arr) { while (1) { IIC_Start(); IIC_SendByte(devAddr); if (IIC_WaitAck()) break; } IIC_SendByte(addr); IIC_WaitAck(); IIC_Start(); IIC_SendByte(devAddr | 0x01); IIC_WaitAck(); while (--len) { *arr++ = IIC_RecByte(); IIC_Ack(1); } *arr = IIC_RecByte(); IIC_Ack(0); IIC_Stop(); }
注:函数
// [chl]选择通道 uchar ADC(uchar chl) { uchar value; while (1) // 等待设备应答 { IIC_Start(); IIC_SendByte(0x90); if (IIC_WaitAck()) break; } IIC_SendByte(chl); IIC_WaitAck(); IIC_Stop(); IIC_Start(); IIC_SendByte(0x91); IIC_WaitAck(); value = IIC_RecByte(); IIC_Ack(0); IIC_Stop(); return value; // 需转换为电压值 }
void DAC(uchar value) // 输入值须要转换 { while (1) { IIC_Start(); IIC_SendByte(devAddr); if (IIC_WaitAck()) break; } IIC_SendByte(0x40); IIC_WaitAck(); IIC_SendByte(value); IIC_WaitAck(); IIC_Stop(); }
注:ui
// DS18B20 // XXXX YYYY YYYY ZZZZ // [X]正负(0-正 1-负) [Y]温度整数值 [Z]温度小数值(Z * 0.0625) uchar Temper_Read() { uchar temp, Tl, Th; Init_DS18B20(); // DS18B20 初始化 Write_DS18B20(0xcc); // 跳过 ROM 的字节命令 Write_DS18B20(0x44); // 开始转换指令 Delay_OneWire(200); // 延时一段时间 Init_DS18B20(); // DS18B20 初始化 Write_DS18B20(0xcc); // 跳过 ROM 的字节命令 Write_DS18B20(0xbe); // 读取指令 Tl=Read_DS18B20(); // 读低八位 Th=Read_DS18B20(); // 读高八位 temp = (Th << 4) | (Tl >> 4); // 只取整数 return temp; }
// DS1302 writeDS1302(0x8E, 0); // 关闭写保护 // 突发模式:必须一次性读写所有 8 个字节 // [0xBF]读 [0xBE]写 writeByte(0xBF); // 突发读 writeByte(0xBE); // 突发写
注:波特率为 9600bps.net
// UART void UartInit(void) //9600bps@11.0592MHz { SCON = 0x50; // 8位数据,可变波特率 AUXR |= 0x40; // 定时器1时钟为Fosc,即1T AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器 TMOD &= 0x0F; // 设定定时器1为16位自动重装方式 TL1 = 0xE0; // 设定定时初值 TH1 = 0xFE; // 设定定时初值 ET1 = 0; // 禁止定时器1中断 TR1 = 1; // 启动定时器1 ES = 1; // 容许串口中断 EA = 1; // 开启总中断 } void UARTInter() interrupt 4 { if (TI == 1) { TI = 0; // 手动清除中断标志 } if (RI == 1) { RI = 0; // 手动清除中断标志 SBUF = SBUF + 1; } }
// 超声波测距 #define nop() {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();} uint echo() { uchar i; uint distance; initTimer(); // 起始信号 out = 0; for (i = 0; i < 16; i++) { out = ~out; nop();nop();nop();nop();nop(); nop();nop();nop();nop();nop(); } // 接收信号 while (!in); TR0 = 1; while ((in == 1) && (TF0 == 0)); // 信号结束或计时器计满 TR0 = 0; // 计算 if (TF0) // 计时器计满,超出测量范围 { distance = 0; TF0 = 0; } else { distance = (uint) (TH0 << 8) | TL0; distance *= 0.017 * 1.085; // 单位 cm (1.085 为偏差补偿) } return distance; }
注:code
OSC 框表示时钟频率,由于1个机器周期等于12个时钟周期,因此那个 d 就等于12。下边 GATE
右边的那个门是一个非门电路,再右侧是一个或门,再往右是一个与门电路。xml图上能够看出来,下边部分电路是控制了上边部分,那咱们先来看下边是如何控制的,咱们以定时器0为例。htm
TR0 和下边或门电路的结果要进行与运算,TR0 若是是0的话,与运算完了确定是0,因此若是要让定时器工做,那么 TR0 就必须置1。
这里的与门结果要想获得1,那么前面的或门出来的结果必须也得是1才行。在 GATE
位为1的状况下,通过一个非门变成0,或门电路结果要想是1的话,那 INT0 即 P3.2 引脚必须是1的状况下,这个时候定时器才会工做,而
INT0 引脚是0的状况下,定时器不工做,这就是 GATE 位的做用。当 GATE 位为0的时候,通过一个非门会变成1,那么无论 INT0 引脚是什么电平,通过或门电路后都确定是1,定时器就会工做。
要想让定时器工做,就是自动加1,从图上看有两种方式,第一种方式是那个开关打到上边的箭头,就是 C/T =0 的时候,一个机器周期 TL
就会加1一次,当开关打到下边的箭头,即 C/T =1 的时候,T0 引脚即 P3.4 引脚来一个脉冲,TL 就加1一次,这也就是计数器功能。
极客学院_5.3 单片机定时器的寄存器:http://wiki.jikexueyuan.com/project/mcu-tutorial-one/timer-register.html
// 频率测量 NE555 uint fre; uchar count = 0; void initNE555Fre() { TMOD = 0x15; // T1:定时器 T0:计数器 TH0 = TL0 = 0; // 计数清零 TL1 = 0x00; // 设置定时初值 TH1 = 0x4C; // 设置定时初值 TF0 = TF1 = 0; TR0 = TR1 = 1; ET1 = 1; EA = 1; } void timer() interrupt 3 { TL1 = 0x00; // 设置重装 TH1 = 0x4C; // 设置重装 if (count++ == 20) { count = 0; fre = (uint) (TH0 << 8) | TL0; TL0 = TH0 = 0; } }
sbit PWM = P1^0; // PWM 输出口 uchar HTH, HTL; // 高电平持续时间 uchar LTH, LTL; // 低电平持续时间 // 高电平计数, 低电平计数, 定时计数 uchar HC, LC, TC; bit PWMF = 1; // PWM 标志 void changePWM(uint fre, uchar dc) { float HTime, LTime; float time = 1090000.0 / fre; // 周期 = 10^6毫秒 / 频率(fre) LTime = (time * dc / 100) * 11059200 / 12 / 1000000; HTime = (time - LTime) * 11059200 / 12 / 1000000; if (dc <= 0 || dc >= 100 || fre <= 0) { TC = 255; if (dc <= 0) PWM = 0; else PWM = 1; return; } // 计数计算 if (65536 < HTime) HC = HTime / 65536; else HC = 0; TH0 = HTH = (65536 - HTime) / 256; TL0 = HTL = (uint) (65536 - HTime) % 256; if (65536 < LTime) LC = LTime / 65536; else LC = 0; LTH = (65536 - LTime) / 256; LTL = (uint) (65536 - LTime) % 256; // 初始化 TH0 = TL0 = 0; TC = LC; if (HC != 0) TC = HC; } void startPWM(uint fre, uchar dc) { // PWM 初始化 PWM = 1; TC = HC = LC = 0; // 定时器初始化 TMOD &= 0xf0; TMOD |= 0x01; changePWM(fre, dc); EA = 1; TF0 = 0; ET0 = 1; TR0 = 1; } void stopPWM() { TR0 = 0; PWM = 1; } void PWMTimer() interrupt 1 { // 当占空比为 0 或 100 时保持电瓶不变 if (TC == 255) return; if (!TC--) { if (PWM) { TH0 = HTH; TL0 = HTL; TC = HC; } else { TH0 = LTH; TL0 = LTL; TC = LC; } PWM = ~PWM; } }
单片机中文网:http://c.biancheng.net/cpp/danpianji/ 单片机入门基础教程: https://wiki.jikexueyuan.com/list/microcontrollers/ Bkoak 博客:http://www.bkoak.com/ EEPW 论坛:http://forum.eepw.com.cn/thread/302835/1