STC15F204EA单片机旋转编码器版白光T12控制器代码(开发固件)(by金向维)
- 格式:docx
- 大小:51.12 KB
- 文档页数:9
摘要:基于stc15f200单片机的控温式手枪自给电烙铁与传统的电烙铁在结构上进行了极大的改进,其采用了手枪式的结构,便于操作;自动进给焊丝的功能避免的操作的不当;基于单片机的控温系统保证了焊接的质量。
关键词:电烙铁;手枪式;控温;单片机0 引言众所周知,电烙铁在电子、金属焊接、机械制造等各行业中得到十分广泛的应用。
据了解,普通电烙铁在实际使用过程中存在以下不足:(1)普通电烙铁操作难度系数高,新手难于掌握。
电烙铁在进行焊接操作时需要操作者双手配合工作,但焊接时双手由于长期处于紧张状态而易疲劳,从而造成注意力不能集中。
同时由于左右手配合需要一定的熟练程度,在操作时其焊接的质量和精度很难保证。
(2)普通电烙铁的温度不能准确控制。
在使用过程中当焊接比较大的区域或者焊接比较大的连接件时就需要比较高的焊接温度,若温度低则无法进行焊接;但是当焊接集成电路的引脚时就需要比较低的温度,若温度太高则极易烧毁集成电路或电子元件。
(3)普通电烙铁采用的是直线型,未能结合人机工程的特点。
现有的普通电烙铁,外观轮廓一般是直线型的,没有过多考虑人手的生理结构和操作的手势,在焊接操作时加剧了受到疲劳感,不便使用。
基于上述原因和实践中的经验,现设计了一种新型的单片机控温的手枪式进给电烙铁。
1 手枪式电烙铁机械结构的初步改进本电烙铁的设计主要由烙铁部分、夹持部分和自动进给三部分组成,如图一所示。
烙铁部分由焊枪架体(18)、加热部分(2)、压线板(17)、十字槽盘头螺钉(10)组成,其构成同普通电烙铁;夹持部分由前置卡紧弹簧(4)、前置卡紧滑块(5)、后置卡紧弹簧固定塞(6)、后置卡紧弹簧(7)、反向进给滑块(8)、后置卡紧滑块(9)组成;自动进给部分由焊丝盘安装座(11)、复位弹簧(12)、焊丝盘(13)、封闭板(14)、扳机(15)、换向齿轮(16)组成。
其中,扳机安装在焊枪架体内部,换向齿轮与扳机相连,复位弹簧一端固定在焊枪架体内部,另一端与扳机相连,压线板安装在焊枪架体上,封闭板安装在扳机的上部,封闭板的右侧安装有反向进给滑块,反向进给滑块的内部安装有后置卡紧弹簧,后置卡紧弹簧左端与后置卡紧弹簧固定塞相连,右端与后置卡紧滑块相连,封闭板左侧安装有前置卡紧滑块,前置卡紧弹簧一端与前置卡紧滑块相连,另一端与前置卡紧弹簧固定塞相连,导向管安装在焊枪架体上,导向管的上端安装有加热部分,焊丝盘上加工有焊丝盘安装座,焊丝盘安装座通过十字槽盘头螺钉固定在焊枪架体上。
12345678ABCD87654321DC B ATitle NumberRevisionSize A2Date:5-May-2012 Sheet of File:D:\电路开发\工程\T12控制器\New_Pcb\T12控制器.ddbDrawn By:P2.61P2.72ADC0/P1.03ADC1/P1.14ADC2/P1.25ADC3/P1.36ADC4/P1.47ADC5/P1.58ADC6/P1.69ADC7/P1.710IRC_CLKO/RST/P0.011Vcc 12P0.113Gnd 14P3.0/LOW INT415P3.116P3.2/INT017P3.3/INT118P3.4/T0/CLKOUT119P3.5/T1/CLKOUT020P3.6/LOW INT221P3.7/LOW INT322P2.0/RSTOUT_LOW 23P2.124P2.225P2.326P2.427P2.528STC15F200U1STC15F200-28PIN_A+5C2100nf+C110uf上电后输出低电平,在复位期间也是输出低电平.T12_CTRL 123J1UART更新与调试TTL 串口RxD TxDRxDTxD T12_ADC 618D1TL431R191KTL431_ADCTL431 2.49V 基准+5TL431_ADC NTC_ADC DPY_BDPY_A DPY_C DPY_D DPY_E DPY_F DPY_G DPY_DP DPY_DIG3DPY_DIG2DPY_DIG1ENCODER_A ENCODER_D ENCODER_BQ2s8050R244.7kR234.7kQ1MOSFET P 9435+24T12_CTRL12J4T12_OUTD2LED RedR264.7k 加热状态指示T12_AMPR201kT12驱动48231U2ALM358R410kR211k R274.7kC3100nf56748U2BLM358VCC_OPT12_AMPR2820kR221kR3010kT12_ADCD45.1V对于936 建议预留焊0805焊盘 断开后转接936热电偶12J2936_SWITCH_A 1322_AMP12J3936_SWITCH_BR2920kR254.7k拆自3R33模块, 5.2V 左右输入端对地, 输出电压实测39mv 国产LM358D31N4148T12热电偶信号放大 936部分暂时忽略T12 0-500 0.000-16.748mv℃单片机ADC 参考电压等于VCC 约5v代码中按照放大器269倍增益计算既在500度时4505.212mv 只要放大器满足此条件可以用别的也可以改变电路A 1C 2B 3D 4E5Encoderencoder1ROTARYENCODERR110k R210k +5C410nfC510nfR310kENCODER_AENCODER_B ENCODER_D 软件消抖,可以不使用.旋转编码开关控制a b f c g d e DIG1a b c d e f g abc d e fgdpdpdp a b f c g d e DIG2dp a bf cg d e DIG3dp D I G 1D I G 1D I G 2D I G 2D I G 3D I G 3DS1DPY_7-SEG_DP_3I/O 口直接驱动LED 数码管R6470R7470R8470R9470R10470R11470R12470R13470R14470R15470R164703位共阴数码管驱动DPY_A DPY_B DPY_CDPY_DDPY_EDPY_F DPY_G DPY_DPDPY_DIG1DPY_DIG2DPY_DIG3R18NTC-MF52AT 10K 5% B 3950 %1R1710k %1C610nf基于NTC 热敏电阻 NTC-MF52AT 10K 5% B 3950 %1+5NTC_ADC滤波可省略冷端参考ON/OFF 1VIN 2GND3GND4VOUT 5ADJ 6KIS-3R33S U3KIS-3R33SD51N4004+C733uf 30V+24DC 19.5-24V需要拆除稳压二极管R510k可选? 没示波器看不到纹波情况+C833uf-100uf 25vC90.1-10uf+55V 输出修改输出电压为5V VCC_OP给LM358供电DC-DC 转换STC15F204EA 白光T12控制器 V 1.00 By GOODCODE。
单片机编码器编程实例-回复“单片机编码器编程实例”编码器是一种常用的输入设备,广泛应用于各种电子设备中。
在单片机编程中,编码器常被用于控制和监测电机运动、旋转角度的测量以及用户界面交互等方面。
本文将以编码器编程为主题,一步一步介绍如何在单片机中实现编码器的功能。
第一步:了解编码器的基本原理和工作方式编码器是一种将旋转运动转化为电信号的设备。
常见的编码器有旋转编码器和线性编码器两种。
旋转编码器通常由一对光电传感器和一个带有刻度盘的旋转轴组成。
当旋转轴旋转时,光电传感器会感知到刻度盘的变化,并将其转化为电信号输出。
线性编码器则是通过传感器感知物体的移动,并将其转化为电信号输出。
第二步:了解编码器的输出类型和工作原理编码器的输出类型有两种,一种是增量式编码器,另一种是绝对式编码器。
增量式编码器通常输出两路信号,一路表示方向(A相信号),另一路表示旋转角度(B相信号)。
绝对式编码器则输出更多的信号,可以精确表示旋转位置或线性位移。
第三步:选择合适的编码器类型和接口在单片机编程中,通常会选择增量式编码器,因为其相对简单且较为常用。
选择适合的编码器接口是编程前必须考虑的因素之一。
常见的编码器接口有两种:脉冲计数接口和磁编码接口。
对于脉冲计数接口,编码器输出的脉冲信号通过单片机的IO口进行读取;对于磁编码接口,编码器输出的信号可以通过SPI、I2C等通信协议进行读取。
第四步:编写初始化函数在进行编码器编程之前,首先需要编写初始化函数,对编码器进行初始化设置。
初始化函数主要包括设置IO口的输入输出方向、使能编码器等操作。
第五步:编写中断服务函数编码器的工作是通过中断来实现的。
当编码器发生旋转或位移时,会产生相应的中断信号,通过中断服务函数来处理这些信号。
中断服务函数主要包括读取编码器的脉冲信号、计算旋转角度或位移,以及对应的控制逻辑。
第六步:编写主程序逻辑在编写主程序逻辑时,可以根据需要选择编码器的工作模式和功能。
/*************STC15F204EA单片机旋转编码器版白光T12控制器代码(开发固件)(by金向维)******************* /#include <> //单片机头文件,24MHz时钟频率#include "" //头文件unsigned char code duanma[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x73}; //共阴数码管段码数据(0,1,2,3,4,5,6, 7,8,9),倒数第二个是显示负号-的数据,倒数第一个是显示字母P的数据unsigned int code wendubiao[62]={924,959,996,1033,1071,1110,1150,1190,1232,1273,1315,1358,1401,1443 ,1487,1501,1574,1619,1663,1706,1751,1756,1776,1810,1853,1903,1958,2017,2078,2 141,2204,2266,2327,2387,2444,2500,2554,2607,2657,2706,2738,2800,2844,2889,2 931,2974,3016,3056,3098,3139,3179,3218,3257,3296,3333,3372,3408,3446,3484,3 519, 3554,3590}; //根据NTC电阻随温度变化进而引起电压变化得出的数据,用来查表计算室温(进而对热电偶冷端补偿)sbit t12=P2^0; //T12通过控制sbit bw=P3^4; //数码管百位位选为sbit sw=P3^5; //数码管十位位选为sbit gw=P3^6; //数码管个位位选为sbit tihuan=P3^7; //数码管的a段本应该用控制,由于被用来控制T12,所以要用替代sbit encoderb=P1^4; //编码器的b脚接sbit encodera=P3^2; //编码器的a脚接sbit zhendongkaiguan=P0^1; //震动开关接sbit bianmaanniu=P3^3; //编码器的按键接sbit a7=P2^7; //数码管小数点sbit a6=P2^6; //数码管g段sbit a5=P2^5; //数码管f段sbit a4=P2^4; //数码管e段sbit a3=P2^3; //数码管d段sbit a2=P2^2; //数码管c段sbit a1=P2^1; //数码管d段bit e=1, f=1; //e f 用来保存编码器上一次的状态bit huancunkaiguan=0; //用于改变设定温度后延时显示设定温度(而不是立刻显示t12温度)signed int huancun; //显示函数直接显示huancun,要显示一个数据将必须这个数据赋值给缓存(由于数码管只有三位,为了在显示三位数同时保持四位数的精度,所以实际显示的是数据除以10,并支持显示负数)signed int shiwen; //10倍实际室温,即实际室温乘以10(为了精确)(允许的室温范围为-11度至50度)signed int t12wendu; //T12烙铁头的实际温度(非热电偶的温差)(同样为10倍温度)signed int shedingwendu; //设定温度(范围200~450度)signed int wencha; //T12两个周期间的温差signed int jiareshu; //每200ms加热周期内需要加热的次数(一次等于1ms,相当于加热占空比)unsigned char zhouqijishu; //加热周期200ms计数unsigned int huancunjishu; //用于改变设定温度后延时显示设定温度(而不是立刻显示t12温度)unsigned long cankaodianya0, t12dianya, ntcdianya, dianyuandianya;/********************************1ms延时函数*************************************************/void delay_ms (unsigned int a) //24MHz时钟时的1毫秒延时函数{unsigned int b;while(a--){for(b=0;b<1200;b++);}}/********************************10us延时函数************************************************/void delay_10us (unsigned int a) //24MHz时钟时的10微秒延时函数{unsigned int b;while(a--){for(b=0;b<12;b++);}}/********************************数码管延时关断函数******************************************/ void guanduan (void) //用于关断数码管的位选{delay_ms(1); //延时bw=1; //关断百位sw=1; //关断十位gw=1; //关断个位}/********************************公共函数10(显示)********************************************/ void gonggonghanshu10(unsigned char a){a7=a&0x80; //小数点a6=a&0x40; //ga5=a&0x20; //fa4=a&0x10; //ea3=a&0x08; //da2=a&0x04; //ca1=a&0x02; //btihuan=a&0x01; //a}/********************************显示函数****************************************************/ void display(signed int a) //显示函数(显示实际数据除以10,支持显示负数){unsigned char baiwei, shiwei, gewei, d; //定义百位,十位,个位,每次显示帧数signed int c; //用于处理数字aif(a<0) //如果a是负数c=-a; //取a的相反数else //否则c=a; //就直接取ac=c/10;baiwei=c/100; //计算百位c=c%100;shiwei=c/10; //计算十位c=c%10;gewei=c; //计算个位for(d=0;d<20;d++) //显示部分,每次显示20个循环(20帧){if(a<0) //如果a是负数,则百位显示负号gonggonghanshu10(duanma[10]);else //否则直接显示百位gonggonghanshu10(duanma[baiwei]); //显示百位bw=0; //打开百位guanduan(); //延时关断百位gonggonghanshu10(duanma[shiwei]); //显示十位sw=0; //打开十位guanduan(); //延时关断十位gonggonghanshu10(duanma[gewei]); //显示个位gw=0; //打开个位guanduan(); //延时关断个位}}/********************************ADC公共函数**************************************************/ void gonggonghanshu2(void) //此函数测量单片机电源电压{ADC_CONTR=0x88; //ADC_POWER, SPEED1, SPEED0, ADC_FLAG---ADC_START, CHS2, CHS1, CHS0 delay_10us(2); //延时等待转换结束ADC_RESL=ADC_RESL&0x03; //取转换结果低八位中的低二位cankaodianya0=(ADC_RES*4+ADC_RESL); //把结果转换成十进制数据(10位ADC,最大值1024)dianyuandianya=2549760/cankaodianya0; //计算电源电压,单位mV}/********************************ADC测电压函数************************************************/void adc (void) //ADC函数,用于测量和计算各种电压{signed char a; //查NTC表用gonggonghanshu2(); //公共函数2(此函数功能是测量电源电压,单位mV)ADC_CONTR=0x89; //ADC控制寄存器设置,转换采用最低速度速,低速更精确(测量t12电压务必使用最低速度AD转换,实测高速误差大) delay_10us(2);ADC_RESL=ADC_RESL&0x03;t12dianya=(ADC_RES*4+ADC_RESL);t12dianya=2490*t12dianya/cankaodianya0; //计算t12电压,单位mVADC_CONTR=0x8a; //ADC控制寄存器设置delay_10us(2);ADC_RESL=ADC_RESL&0x03;ntcdianya=(ADC_RES*4+ADC_RESL);ntcdianya=2490*ntcdianya/cankaodianya0; //计算ntc电压,单位mVfor(a=0;wendubiao[a]<ntcdianya;a++) //查表计算室温{if(a>=61) //如果超出表的范围就取允许的最高温度(50度) break; //并且退出查表}shiwen=(a-11)*10; //得出室温(实际室温乘以10)t12wendu=(t12dianya-100)*43*10/260+shiwen; //计算t12的实际温度,其中260为运放增益if(t12wendu<shiwen) //如果t12温度小于室温t12wendu=shiwen; //就取室温if(t12wendu>5000) //如果得出的温度超过500度,说明没有插入烙铁头或参数错误(因为烙铁头的温度不可能超过500度)t12wendu=5000; //显示500作为错误指示(注意显示函数显示的是1/10,所以要显示500,需要赋值5000)if(huancunkaiguan==1) //如果缓存开关开,说明刚刚改变了设定温度huancun=shedingwendu; //于是显示设定温度(而不是t12温度) elsehuancun=t12wendu; //否则直接显示t12温度}/********************************定时器0初始化函数*******************************************/ void timer0init (void) //定时器0初始化程序,24MHz频率下,每1ms中断一次{TMOD=0x00; //定时模式,16位自动重装TH0=0xf8; //计时1msTL0=0x2f;ET0=1; //开启定时器0中断TR0=1; //启动定时器0}/********************************公共函数6(记录编码器状态)**********************************/ void gonggonghanshu6(void){e=encodera; //记录编码器a脚此次状态f=encoderb; //记录编码器b脚此次状态}/********************************编码器函数(正常加热模式调用)********************************/ void bianmaqi(void){if(e==1&&f==1&&encodera==1&&encoderb==0) //和前一次状态比较确定为右旋{shedingwendu=shedingwendu+100; //步进if(shedingwendu>4500) //最高允许450度shedingwendu=4500;huancun=shedingwendu; //显示改变后的设定温度huancunkaiguan=1; //打开缓存开关(用于延时显示设定温度秒)huancunjishu=0; //重新开始缓存计数}if(e==1&&f==1&&encodera==0&&encoderb==1) //和前一次状态比较确定为左旋{shedingwendu=shedingwendu-100; //步进if(shedingwendu<2000) //最低允许200度shedingwendu=2000;huancun=shedingwendu; //显示改变后的设定温度huancunkaiguan=1; //打开缓存开关(用于延时显示设定温度秒)huancunjishu=0; //重新开始缓存计数}gonggonghanshu6(); //记录编码器状态}/********************************定时器0中断函数********************************************/void timer0(void) interrupt 1 //定时器0中断函数,检测编码器,掉电存储等操作(仅用于正常工作模式){unsigned char buchang;bianmaqi(); //调用编码器函数if(huancunkaiguan==1) //延时显示计数huancunjishu++;zhouqijishu++; //加热周期计数if(jiareshu>190) //最多加热190msjiareshu=190;if(zhouqijishu<=jiareshu) //如果当前计数小于等于加热数t12=1; //就加热else //否则t12=0; //不加热if(t12wendu==5000) //如果t12温度为500,说明没有插入烙铁头或参数严重错误t12=0; //停止加热if(huancunjishu==1500) //如果达到了设定温度延时显示的秒{huancunkaiguan=0; //关闭缓存开关huancunjishu=0; //停止缓存计数huancun=t12wendu; //由显示设定温度改为显示t12温度}if(zhouqijishu==200) //t12停止加热后2ms再检测温度(给电容留出放电时间,防止检测的温度偏高){adc(); //检测电压,计算温度zhouqijishu=0; //重新开始加热周期计数////////////////////以下为加热算法(请自行理解,不作注释)//// /////////////if(t12wendu>shedingwendu){if(t12wendu-shedingwendu<=20)jiareshu=(shedingwendu-1500)/160;elsejiareshu=0;}if(t12wendu<=shedingwendu){wencha=shedingwendu-t12wendu;if(wencha>20){buchang++;if(buchang>150)buchang=150;}elsebuchang=0;if(shedingwendu-t12wendu>=300)jiareshu=198;else if(shedingwendu-t12wendu>=200)jiareshu=160;else if(shedingwendu-t12wendu>=150)jiareshu=130;else if(shedingwendu-t12wendu>=100)jiareshu=90+wencha/2+buchang;else if(shedingwendu-t12wendu>=50)jiareshu=50+buchang*2;elsejiareshu=(shedingwendu-1000)/80+wencha*2/3+buchang;}}}/********************************主函数*****************************************************/ void main (void) //主函数{P1M0=0x00; //P1除,,为输入模式外均为正常模式P1M1=0x07;P1ASF=0x07; //设置P1相应ADC转换的I/O口为ADC输入模式P2M0=0xff; //P2都是推挽模式P2M1=0x00;P3M0=0xf0; //,,,为推挽模式,,为输入模式,P3M1=0x06; //其余正常模式ADC_CONTR=0xe0; //打开ADC电源shedingwendu=3000; //设为300度IE=0x88; //打开定时器0中断,关闭定时器1中断timer0init(); //初始化定时器0while(1){display(huancun); //数码管显示数据}}。
//**************************************************************************** //// STC12C5A60S2可编程时钟模块////// 说明:STC12C5A60S2单片机有三路可编程时钟输出CLKOUT0/T0/P3.4// CLKOUT1/T1/P3.5、CLKOUT2/P1.0//// 涉及寄存器:AUXR(辅助寄存器)、WAKE_CLKO(时钟与系统掉电唤醒控制寄存器) // BRT(独立波特率发生器定时器寄存器)//// 程序说明:// 本程序可选实现P3.4输出CLKOUT0时钟、P3.5输出CLKOUT1时钟// P1.0输出CLKOUT2时钟//////************************************************************************** **//#include <STC12C5A60S2.H>#include <intrins.h>//#define Port_BRT //如果想测试独立波特率发生器时钟输出请打开此句//若想测试CLKOUT1和CLKOUT0请注释此句#ifdef Port_BRT /*条件编译独立波特率发生器时钟输出*///*********************************//// CLKOUT2时钟初始化 ////*********************************//void CLKOUT_init(void){WAKE_CLKO = 0x04; //Bit2-BRTCLKO 允许P1.0配置为独立波特率发生器的时钟输出//BRT工作在1T模式下时的输出频率 = Sysclk/(256-BRT)/2 //BRT工作在12T模式下时输出频率 = Sysclk/12/(256-BRT)/2 AUXR = 0x14; //Bit4-BRTR 允许独立波特率发生器运行//Bit2-BRTx12 BRT工作在1T模式下BRT = 0xff; //更改该寄存器的值可实现对输出的时钟频率进行分频}#else /*条件编译CLKOUT0时钟输出*///*********************************//// CLKOUT0时钟和CLKOUT1初始化 ////*********************************//void CLKOUT_init(void){WAKE_CLKO = 0x03; //允许将P3.4/T0脚配置为定时器0的时钟输出CLKOUT0//T0工作在1T模式时的输出频率 = SYSclk/(256-TH0)/2//T0工作在12T模式时的输出频率 = SYSclk/12/(256-TH0)/2 //1T指的是每1个时钟加1,是普通C51的12倍//12T指的是每12个时钟加1与普通C51一样//允许将P3.5/T1脚配置为定时器1的时钟输出CLKOUT1,只能工作在定时器模式2下//T1工作在1T模式时的输出频率 = SYSclk/(256-TH0)/2//T1工作在12T模式时的输出频率 = SYSclk/12/(256-TH0)/2 //1T指的是每1个时钟加1,是普通C51的12倍//12T指的是每12个时钟加1与普通C51一样AUXR = 0xc0; //T0定时器速度是普通8051的12倍,即工作在1T模式下//T1定时器速度是普通8051的12倍,即工作在1T模式下TMOD = 0x22; //定时器0工作模式为方式2,自动装载时间常数//定时器1工作模式为方式2,自动装载时间常数TH0 = 0xff; //更改该寄存器的值可实现对输出的时钟频率进行分频TL0 = 0xff;TH1 = 0xff; //更改该寄存器的值可实现对输出的时钟频率进行分频TL1 = 0xff;TR1 = 1;TR0 = 1;}#endif//**********************************//// 主程序////**********************************//void main(){CLKOUT_init();while(1);}//**************************************************************************** //// STC12C5A60S2系统时钟模块////// 说明: STC12C5A60S2单片机有两个时钟源,内部R/C振荡时钟和外部晶体时钟// 出厂标准配置是使用外部晶体或时钟////// 涉及寄存器:CLK_DIV(时钟分频寄存器)// 由该寄存器的Bit0-2组合可实现对时钟源进行0、2、4、8、16 // 32、64、128分频// //// 程序说明:// 对外部时钟进行分频得到Sysclk,然后经过P1.0的独立波特率// 时钟输出功能Sysclk/2输出时钟频率//**************************************************************************** //#include <STC12C5A60S2.h>#include <intrins.h>#define Bus_clk 12 //若要修改系统时钟直接在此处修改//12 为 12M 的sysclk//6 为 6M 的sysclk//3 为 3M 的sysclk//1500 为 1.5M 的sysclk//750 为 750kHz 的sysclk//375 为 375kHz 的sysclk//187500 为 187.5kHz 的sysclk//93750 为 93.75kHz 的sysclk//*********************************************//// 系统时钟初始化 ////*********************************************//void Sysclk_init(void){WAKE_CLKO = 0x04; //配置P1.0口为频率输出AUXR = 0x14; //允许波特率时钟工作//工作模式为1TBRT = 0xff;#if( Bus_clk == 12 )CLK_DIV = 0x00;#elif( Bus_clk == 6 )CLK_DIV = 0x01;#elif( Bus_clk == 3 )CLK_DIV = 0x02;#elif( Bus_clk == 1500 )CLK_DIV = 0x03;#elif( Bus_clk == 750 )CLK_DIV = 0x04;#elif( Bus_clk == 375 )CLK_DIV = 0x05;#elif( Bus_clk == 187500 )CLK_DIV = 0x06;#elif( Bus_clk == 93750 )CLK_DIV = 0x07;#endif}//**********************************************//// 主程序////**********************************************//void main(){Sysclk_init();while(1);}//**************************************************************************** //// STC12C5A60S2系统省电模块////// 说明: STC12C5A60S2单片机有三种省电模式以降低功耗.空闲模式,低速模式// 掉电模式////// 涉及寄存器:PCON(电源控制寄存器)// Bit0 - IDL 控制单片机进入IDLE空闲模式// Bit1 - PD 控制单片机进入掉电模式// //// 程序说明:程序实现让单片机先工作一阵子(通过P0^3指示灯显示)// 然后进入掉电状态,利用外部中断0口来唤醒单片机工作// 唤醒后单片机将通过P0^0-3口的灯闪烁显示开始工作////************************************************************************** **//#include <STC12C5A60S2.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar Power_Down_Flag = 0; //进入掉电状态标志sbit Chip_Start_LED = P0^0; //单片机开始工作指示灯sbit Power_Down_LED_INT0 = P0^1; //INT0口掉电唤醒指示灯sbit N_Power_Down_LED_INT0 = P0^2; //INT0口没有唤醒指示灯sbit Normal_Work_LED = P0^3; //正常工作指示灯sbit Power_Down_Wakeup_INT0= P3^2; //外中断唤醒输入口void Delay_ms( uint time );void Normal_work(void);void Intp_init(void);void After_Powr_Down(void);//***********************************//// 软件延时 ////***********************************//void Delay_ms( uint time ){uint t; //延时时间 = (time*1003+16)us while(time--){for( t = 0; t < 82; t++ );}}//***********************************//// 正常工作指示//***********************************//void Normal_work(void){Normal_Work_LED = 1;Delay_ms(500);Normal_Work_LED = 0;Delay_ms(500);}void After_Power_Down(void){uchar i ;for( i = 0; i < 100; i++ ){P0 = 0x0f;Delay_ms(500);P0 = 0x00;Delay_ms(500);}}//***********************************//// 中断初始化 ////***********************************//void Intp_init(void){IT0 = 0; //外部中断源0为低电平触发EX0 = 1; //允许外部中断EA = 1; //开总中断}//***********************************//// 主程序 ////***********************************//void main(){uchar j = 0;uchar wakeup_counter = 0; //记录掉电次数P0 = 0x00;Chip_Start_LED = 1; //单片机开始工作Intp_init(); //外中断0初始化while(1){P2 = wakeup_counter;wakeup_counter++;for( j = 0; j < 250; j++ ){Normal_work(); //系统正常工作指示}Power_Down_Flag = 1; //系统开始进入掉电状态PCON = 0x02;_nop_();_nop_();_nop_();_nop_();After_Power_Down(); //掉电唤醒后}}//**********************************//// 中断服务//**********************************//void INT0_Service(void) interrupt 0{if( Power_Down_Flag ) //掉电唤醒状态指示 {Power_Down_Flag = 0;Power_Down_LED_INT0 = 1;while( Power_Down_Wakeup_INT0 == 0 ){_nop_(); //等待高电平}Power_Down_LED_INT0 = 0;}else //未掉电状态{N_Power_Down_LED_INT0 = 1; //不是掉电唤醒指示while( Power_Down_Wakeup_INT0 == 0 ){_nop_();}N_Power_Down_LED_INT0 = 0;}}//**************************************************************************** //// STC12C5A60S2 A/D转换模块////// 说明: STC12C5A60S2单片机有8路10位高速AD转换器,P1^0-P1^7//// 涉及寄存器:P1ASF(模拟功能控制寄存器)、ADC_CONTR(ADC控制寄存器)// ADC_RES、ADC_RESL(转换结果寄存器)//// 注意: 1、初次打开内部A/D模拟电源需适当延时等内部模拟电源稳定后,再启动A/D转换// 启动A/D后,在转换结束前不改变任何I/O口的状态,有利于高精度A/D 转换// 若能将定时器/串行/中断系统关闭更好。
1.航空座- - T12负极SW接震动开关+T12正极E接T12外壳2.接12-20V直流电3.加热指示灯,加热时亮。
4.温度校准当数码管显示温度与T12实际温度偏低时顺时针旋转。
偏低时逆时旋转。
5.加温正常使用时,按下编码器,顺时针旋转,则是加温模式,在现有的基础上增加50℃。
6.休眠正常使用时,按下编码器,逆时针旋转,则是休眠模式,T12保持在200℃。
或者SW在3分钟后没有低电平,也可以进入休眠。
取消休眠模式,可以按一下编码器,或者旋一下编码器,或者SW接T12负极。
7.调温改变温度的时候,此处亮。
8.编码器P01 ADC参考电压(通过测TL431获得)P02 NTC修正(通过将设定温度到最低观察数码管上的读数) P03 运放输入失调电压修正值P04 热电偶放大器增益P05 PID参数pGainP06 PID参数iGainP07 PID参数dGainP08 自动关机时间设置3-50分钟P09 恢复出厂设置P10 温度步进设置P11热电偶放大器增益常见故障排除方法:1.数码管显示不稳定,不能稳定在设定温度。
常见如果是使用全新的T12时,会出现温度乱跳的情况。
解决方法是通电3-5分钟,然后断电,通电。
此时T12芯内部稳定后,数码管显示也会趋于稳定,此时如果仍然不稳定,可在T12手柄的+ - 极并接一个0.1uf/50V的电容。
如果仍然不能稳定,可以调节温度校准电位器。
2.对于SW未接震动开关,控制器在3分钟后会自动进入休眠200℃,若觉得使用不便,SW和T12 + 接104的电容可取消休眠功能。
恢复出厂设置方法按住编码器中键,开机,松开中键,数码管会显示P01 然后会自动跳到249长按中键,松开,数码管显示P02后变为000,长按中键,数码管显示P03后变为000 长按中键,松开,数码管显示P04后变为270 长按中键,松开,数码管显示P05后变为064 长按中键,松开,数码管显示P06后变为002 长按中键,松开,数码管显示P07后变为016 长按中键,松开,数码管显示P08后变为010 长按中键,松开,数码管显示P99后变为000 此时旋一下编码器,使数码管为001 长按中键后,即可恢复出厂设置。
STC单片机唯一ID保护的例子及思路(摘自STC-ISP V6.XX【重要说明】部分)关于ID号在大批量生产中的应用方法(较多客户的用法)(转载)先烧一个程序进去(选择下次下载用户程序时不擦除用户EEPROM区),读程序区的ID号(STC15系列是程序区的最后7个字节),经用户自己的复杂的加密算法对程序区的ID号加密运算后生成一个新的数---用户自加密ID号,写入STC15系列用户的EEPROM区的EEPROM。
再烧一个最终出厂的程序进去(选择下次下载用户程序时将用户EEPROM区一并擦除),在用户程序区多处读程序区的ID号和用户自加密ID号比较(经用户自己的复杂的解密算法解密后),如不对应,则6个月后随机异常,或200次开机后随机异常。
最终出厂的程序不含加密算法。
另外,在程序区的多个地方判断用户自己的程序是否被修改,如被修改,则6个月后随机异常,或200次开机后随机异常,将不用的用户程序区用所谓的有效程序全部填满。
《应用笔记》单片机加密保护的几种方式:1、法律保护由完善的法律加强对盗版的打击。
在单片机程序里添加自己的版权、LOGO标记等,作为法庭上的证据(当然要加密保存,并反跟踪,程序运行中要校验是否被修改,如是则作相应的处理)。
2、技术保护。
其实理论上所有的单片机加密都会被破解,只是成本的问题(含时间成本、金钱成本等)。
只要做到解密的成本足够大,让破解者觉得无利可图即算成功!通常是加密的容易而破解难。
现代芯片的加密主要有工艺上缩小线宽、将保密位深埋、读写协议保密、读取敏感区域时自动重启等等方法,让破解者不能取得内部BIN执行代码。
假如一个系统的成本为:开发+测试+投产只需5万元,而破解得到BIN 文件却要10万元,这时哪谁还去做破解的傻事??而且如果开发者使用了关联单片机唯一ID的保护方式,哪怕破解者千辛万苦取得了BIN文件还不能直接使用,就可以大大增加了系统的保密性。
加密者使用唯一ID的加密就像PC软件使用USB加密狗加密方式和银行网银的证书加密方式,都是通过唯一的认证工具,让系统识别合法用户。
/*T8接T3和T2;或T8接T3,T7接T2;调电位器R36可改变内部10位AD转换0和1通道的电压Vin0或Vin1,采样周期5ms;送AD的电压用万用表在T8(对T6)测量;按照十六进制,0通道数字量由LCD显示(1行);1通道数字量由LCD显示(2行);0通道对应理论值在左边5个数码管显示(1个符号位,2个整数位,2个小数位);1通道对应理论值在右边5个数码管显示(1个符号位,2个整数位,2个小数位);研究2通道间是否需要适当延时*/#in clude <15f2k.h>#in clude <ab sacc.h>#d efine u8c uns igned char code//存放于代码中的无符号8位字符型缩写定义#de fineu8 unsi gnedchar//无符号8位字符型缩写定义#defin e u16 un signe d int //无符号16位整型缩写定义#def ine w ritec md XBYTE[0xEC FF]//1602写指令端口地址,E正脉冲有下降沿(A12=0),R/W=A9=0写,RS=A8=0写指令#defin e rea dstat e XB YTE[0xEEFF]//1602读状态端口地址,E正脉冲有高电平(A12=0),R/W=A9=1读,RS=A8=0读状态#de finewrite data XBYT E[0xE DFF]//1602写数据端口地址,E正脉冲有下降沿(A12=0),R/W=A9=0写,R S=A8=1读数据#defi ne Di splay seg X BYTE[0x7FF F]//数码管段码锁存器写端口地址(A15=0)#defi ne Di splay bit X BYTE[0xBFF F]//数码管位码锁存器写端口地址(A14=0)#defi ne LC D_CLR0x01 //清屏,清DD RAM内容为空,AC=00H#defi ne LC D_MOD E 0x38 //模式设置,001DLN F**,D L=1是8位数据接口,N=1两行显示,F=0是5*7点阵字符#def ine L CD_ON0x0c //显示开关控制,00001DCB,D=1开显示,C=0关光标,B=0关闪烁#de fineLCD_A_MODE 0x06//输入方式设置,000001I/DS,I/D=1数据读写后A C自动增1,S=0数据读写后画面不动b it new_cycl e_fla g=0; //有新采样数据标志,1有新数据sb it LSIG N=P1^6; //左边的符号位数码管公共端连接引脚,=0可能亮sbit RS IGN=P1^7; //右边的符号位数码管公共端连接引脚,=0可能亮u8r_kTH,m_kT H,r_k TL,m_kTL;//0通道和1通道AD转换结果u8 di spbuf[10],statu s,i; //10个数码管显示段码缓存区数组和AD转换状态及计算用中间变量int Vi n0x100,Vin1x100; //据AD值推算的0通道和1通道输入的100倍(显示用) u16A xx,j; //显示时用的中间变量float Vi n0,Vi n1; //据AD值推算的0通道和1通道输入-11.0V~+10.914Vu8 M=0; //扫描显示位计数变量定义u8cSG[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x 79,0x71};//0-F段码表u8c BT[10]={0xfe,0xfd,0xfb,0xf7,0xff,0xef,0xdf,0xbf,0x7f,0xff};//位码表u8c dis p1[16]={'0',' ','C','h','a','n','n','e','l',' ','A','D',' ',' ','H',''};u8c di sp2[16]={'1','','C','h','a','n','n','e','l',' ','A','D',' ',' ','H',' '};/***********LCD写指令************/voi d LCD write cmd(c har c md) //要传递指令{ w hile((read state&0x80)!=0); //查询LC D忙否?B F=1表示忙,循环,直到BF=0退出循环wr itecm d=cmd; //写指令,即把指令送[0xE3F F]端口}/***********L CD写数据************/v oid L CDwri tedat a(cha r dat) //要传递数据{ whil e((re adsta te&0x80)!=0); //查询LCD忙否?BF=1表示忙,循环,直到B F=0退出循环write data=dat;//写数据,即把数据送[0xE7FF]端口}/***********LCD初始化************/void LCD_init(void) //清屏/8位数据接口/1行/5*7点阵字符/关显示/AC自动增1{ L CDwri tecmd(LCD_MODE); //写模式设置指令 LCDw ritec md(LC D_ON); //写显示开关控制指令LCDwr itecm d(LCD_A_MO DE);//写输入方式设置指令L CDwri tecmd(LCD_CLR);//写清屏指令}/*******1602液晶屏幕初始化*******/voi d Dis play_init(void)//1602显示初始化{ LC Dwrit ecmd(0x80); //写指令,设置DDRA M指针AC=0x00fo r(i=0;i<16;i++) LCDw rited ata(d isp1[i]);//往第1行写数据:"0chan nel A D: H "LCDwr itecm d(0xc0); //写指令,设置DD RAM指针AC=0x40for(i=0;i<16;i++) LC Dwrit edata(disp2[i]);//往第2行写数据:"1ch annel AD: H "}/**********内部AD初始化**********/voi d AD_init(void)//内部AD初始化{ CLK_DIV&=0xDF; //MC KO_S1 MCKO_S0 A DRJ T X_RX- CLK S2CL KS1 C LKS0 //A DRJ=0,ADC_RES[7:0]存高8位ADC结果,AD C_RES L[1:0]存低2位ADC结果AD C_CON TR=0x80; //开A/D转换电源 for(j=0;j<10000;j++); //适当延时,一般延时1ms以内即可P1A SF=0x03; //开启P1.0和P1.1作为0通道和1通道模拟量输入通道A DC_CO NTR=0xC0;//ADC_POWER SPEE D1 SP EED0ADC_F LAG A DC_ST ART C HS2 C HS1 C HS0=1 10 0 0 000B//选择180个时钟周期转换1次,暂时不启动AD转换,选择0通道for(j=0;j<200;j++);//适当延时,20u s~200us即可}/***********T0T1初始化***********/v oid T0T1_i nit(v oid) //10数码管扫描1周AD转换1次,每管显1ms,AD周期10ms{ AUX R|=0x c0; //T0、T1定时器时钟1T模式,T0定时1m s,AD时间127.3us TMOD=0x20; //设置定时器模式,T0方式0定时,T1方式2定时T L0=0x66; //频率=11059200/(65536-0xea66)=1999.855Hz TH0=0xea; //定时周期=1/1999.855=0.000500036s=0.500036msEA=1;//允许中断E T0=1;//允许T0中断TR0=1; //定时器0开始计时}/*AD值倒推输入电压显示缓存区的更新*/voiddisp_g(voi d) //A D值倒推输入电压显示缓存区的更新{ i f(Vin0x100<0) //如果据0通道AD值推算的输入Vin0的100倍是负数{ Axx=-Vin0x100; //取绝对值 disp buf[9]=0x40; //符号位数码管对应送负号的段码}els e //据0通道AD值推算的输入Vin0的100倍是正数 { Ax x=Vin0x100; //取据AD值推算的输入Vi n0的100倍 dis pbuf[9]=0x00; //符号位数码管对应送正号的段码}i=(u8)(Axx/1000); //计算电压伏特十位 disp buf[8]=SG[i]; //电压十位数码管显示缓存更新段码 i=(u8)(Ax x/100%10); //计算电压伏特个位d ispbu f[7]=SG[i]|0x80; //电压个位数码管显示缓存更新段码(含小数点)i=(u8)(Axx/10%10); //计算电压小数后第1位dispb uf[6]=SG[i]; //电压小数后第1位数码管显示缓存更新段码i=(u8)(Axx%10);//计算电压小数后第2位d ispbu f[5]=SG[i]; //电压小数后第2位更新i f(Vin1x100<0) //如果据1通道AD值推算的输入Vin1的100倍是负数{ Axx=-Vin1x100; //取绝对值 disp buf[4]=0x40; //符号位数码管对应送负号的段码}els e //据1通道AD值推算的输入Vin1的100倍是正数 { Ax x=Vin1x100; //取据AD值推算的输入Vi n1的100倍 dis pbuf[4]=0x00; //符号位数码管对应送正号的段码}i=(u8)(Axx/1000); //计算电压伏特十位 disp buf[3]=SG[i]; //电压十位数码管显示缓存更新段码 i=(u8)(Ax x/100%10); //计算电压伏特个位d ispbu f[2]=SG[i]|0x80; //电压个位数码管显示缓存更新段码(含小数点)i=(u8)(Axx/10%10); //计算电压小数后第1位dispb uf[1]=SG[i]; //电压小数后第1位数码管显示缓存更新段码i=(u8)(Axx%10);//计算电压小数后第2位d ispbu f[0]=SG[i]; //电压小数后第2位更新}/*****AD结果显示缓存区的更新******/void disp_f(vo id) //A D结果显示缓存区的更新{ //0通道A D结果显示缓存区的更新L CDwri tecmd(0x8c); //写指令,设置DDR AM指针A C=0x4di=(r_k TH&0x f0)>>4; //取0通道8位AD数据的十六进制高位 if(i<10)LCDwr iteda ta(i+0x30);//更新AD数十六进制高位(数字)的A SCII码el se LC Dwrit edata(i+0x37); //更新AD数十六进制高位(大写字母)的AS CII码 i=r_kTH&0x0f; //取0通道8位AD数据的十六进制低位i f(i<10) LC Dwrit edata(i+0x30);//更新AD数十六进制高位(数字)的ASC II码 else LCDw rited ata(i+0x37); //更新AD数十六进制高位(大写字母)的ASCI I码LCDwr iteda ta('H'); //LCDwr iteda ta(r_kTL+0x30);//更新A D数十六进制高位(数字)的AS CII码 //1通道AD结果显示缓存区的更新LCD write cmd(0xcc); //写指令,设置DDRAM指针AC=0x4di=(m_kTH&0xf0)>>4; //取1通道8位AD数据的十六进制高位i f(i<10) LC Dwrit edata(i+0x30);//更新AD数十六进制高位(数字)的ASC II码 else LCDw rited ata(i+0x37); //更新AD数十六进制高位(大写字母)的ASCI I码i=m_k TH&0x0f; //取1通道8位AD数据的十六进制低位if(i<10) LCDw rited ata(i+0x30);//更新AD数十六进制高位(数字)的ASCII码e lse L CDwri tedat a(i+0x37);//更新AD数十六进制高位(大写字母)的A SCII码 LC Dwrit edata('H'); //LC Dwrit edata(m_kT L+0x30); //更新AD数十六进制高位(数字)的ASCI I码}/*************主程序*************/voi d ma in(vo id) //{ L CD_in it();//1602液晶显示模块初始化Dis play_init(); //1602液晶屏显示内容初始化 AD_i nit(); //内部AD初始化T0T1_in it(); //T0、T1初始化程序(11.0592MH z)do{ if(new_c ycle_flag==1) //有新采样数据标志,Vs1=-(R6/R5)*V in0=-0.2Vi n0 { //Vs2=-(R10/R8)*Vs1-(R10/R9)*(-5)=2.5+0.2Vin0 //当Vin0=-10V时,Vs2=0.5V;当Vin0=10V时,Vs2=4.5V //N=((2.5+0.2Vin0)/5)*256;V in0=0.09765625*N-12.5//Vs3=-(R17/R18)*Vin1=-0.2Vin1 //V s4=-(R13/R15)*V s3-(R13/R14)*(-5)=2.5+0.2Vin1 Vin0*=(fl oat)r_kTH; //A D转换需要127.3us,抽空做点计算 Vin0-=12.5; // Vin0x100=(int)(Vin0*100); //A D值倒推输入电压的100倍;小数点定点在第7位Vin1*=(flo at)m_kTH; //当V in1=-10V时,Vs4=0.5V;当Vin1=10V时,Vs4=4.5V Vin1-=12.5; //N=((2.5+0.2V in1)/5)*256;Vin1=0.09765625*N-12.5 Vin1x100=(int)(Vin1*100); //A D值倒推输入电压的100倍;小数点定点在第2位disp_g(); //0通道和1通道AD值倒推的输入电压显示缓存区的更新disp_f(); //0通道和1通道AD结果显示缓存区的更新n ew_cy cle_f lag=0; //新采样数据标志清0 }}whil e(1);}/*********T0中断服务程序*********/voi d t0() int errup t 1 u sing1 //0.5m s中断,自动重装,每次均要进行显示处理{ if(M==10) //5ms到了吗?因为0.5ms*10=5ms{ADC_C ONTR|=0x08; //到了5ms,启动0输入通道AD转换 new_cycl e_fla g=1;//置有新采样数据标志 M=0;//M清0s tatus=0; //状态变量先清0 whil e(sta tus==0) st atus=ADC_C ONTR& 0x10;//转换结束否?ADC_C ONTR=0xC1; //ADC_P OWERSPEED1 SPE ED0 A DC_FL AGAD C_STA RT CH S2 CH S1 CH S0=110 00 001B//选择180个时钟周期转换1次,将ADC_FLAG清0,暂时不启动AD转换,选择1通道 r_kTH=A DC_RE S; //读取0通道AD结果的高8位 r_kT L=ADC_RESL&0x03; //读取0通道AD结果的低2位,不用 Vin0=0.09765625; //AD转换需要127.3us,抽空预置常数 ADC_CONT R|=0x08; //启动1输入通道A D转换 Vi n1=0.09765625; // st atus=0; //状态变量先清0while(stat us==0) sta tus=A DC_CO NTR & 0x10;//转换结束否?A DC_CO NTR=0xC0; //A DC_PO WER S PEED1 SPEE D0 AD C_FLA GADC_STAR T CHS2 CHS1 CHS0=1 10 0 0 000B //选择180个时钟周期转换1次,将ADC_FLAG清0,暂时不启动AD转换,选择0通道 m_k TH=AD C_RES; //读取1通道AD结果的高8位m_kTL=ADC_RESL&0x03; //读取1通道AD结果的低2位,不用}RS IGN=1; //关闭右边符号位显示LSI GN=1; //关闭左边符号位显示 Disp laybi t=0xf f; //关闭8个数码管的显示 Disp layse g=dis pbuf[M]; //查显示缓存表送数显的段端口D ispla ybit=BT[M]; //查位码表送数显的位端口if(M==4) R SIGN=0; //扫描到右边符号位则该位显示 if(M==9) LSI GN=0; //扫描到左边符号位则该位显示 M++; //修改下一次的显示位}。
1、运行软件2、参照截图设置(1)选择单片机型号为STC15F204EA(2)IRC频率为33.1776MHz(3)选择程序文件为最新的版本3、串口选择为要使用的端口4、确定控制板为断电状态5、点击下载/编程6、开启控制器电源7、刷入完成8、刷完了之后,断电。
按住旋钮开机进入设置模式吧9、10、正在检测目标单片机 ...单片机型号: STC15F204EA固件版本号: 6.7R当前芯片的硬件选项为:. P3.2和P3.3与下次下载无关. 上电复位时不增加额外的复位延时. 复位引脚用作普通I/O口. 检测到低压时复位. 低压检测门槛电压 : 3.82 V. 低压时不能进行EEPROM操作. 上电复位时,硬件不启动内部看门狗. 上电自动启动内部看门狗时的预分频数为 : 256. 空闲状态时看门狗定时器停止计数. 启动看门狗后,软件可以修改分频数,但不能关闭看门狗 . 下次下载用户程序时,不擦除用户EEPROM区开始测试频率 ...开始调节频率 ...调节后的频率: 33.161MHz (-0.051%)正在重新握手 ... 成功当前的波特率: 57600正在擦除目标区域 ... 完成 ! [0.203"]正在下载用户代码 ... 完成 ! [1.809"]正在设置硬件选项 ... 完成 ! [0.047"]芯片出厂序列号 : 000B0016004E4C更新后的硬件选项为:. P3.2和P3.3与下次下载无关. 上电复位时不增加额外的复位延时. 复位引脚用作普通I/O口. 检测到低压时复位. 低压检测门槛电压 : 3.82 V. 低压时不能进行EEPROM操作. 上电复位时,硬件不启动内部看门狗. 上电自动启动内部看门狗时的预分频数为 : 256. 空闲状态时看门狗定时器停止计数. 启动看门狗后,软件可以修改分频数,但不能关闭看门狗 . 下次下载用户程序时,不擦除用户EEPROM区操作成功 !单片机型号: STC15F204EA。
通过编码开关(旋转编码器)控制数码管的加减一我爱单片机赞助商链接//直上调试好的程序看看能否换个M币哈哈!//通过编码开关(旋转编码器)控制数码管的加减一#include<AT89X52.H>#define uchar unsigned char#define uint unsigned int#define cycle 1 //定义动作周期,编码器旋转多少格有效#define NULL 0 //定义编码器不动作时的还回值#define E_RIGHT 0x0e //定义右旋转还回值#define E_LEFT 0x0f //定义左旋转还回值/*=====数码管位及按键定义=====*/sbit dula=P2^6; //数码管段选,锁存器控制信号sbit wela=P2^7; //数码管位选,锁存器控制信号sbit PINA = P1^0; //定义IOsbit PINB = P1^1;uchar WheelNow,WheelOld,RightCount,LeftCount;/*=====0-9=====A-G=====*/uchar a[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};//数码管显示编码unsignedsled_bit_table[]={0x5f,0x6f,0x77,0x7b,0x7d,0x7e,0xff};/*定义点亮的数码管与数组的关系*//*=====四个数码管显示数据存放处=====*/uchar one,two,three,four;uint wc=0;/*=====函数定义=====*/ void delay(uint x);void display(void);//void key();void led_analyze(uint i);/*====延时函数=====*/ void delay(uint x){uint i;for(i=0;i<x;i++);}/*====显示函数=====*/ void display(void){//送段码dula=0;P0 =a[one];dula=1;dula=0;//数码管位选wela=0;P0=sled_bit_table[0]; //开显示wela=1;wela=0;delay(200); //调用键盘扫描wela=0;P0=sled_bit_table[6];wela=1;wela=0; //关显示dula=0;P0=a[two];dula=1;dula=0;//数码管位选wela=0;P0=sled_bit_table[1]; //开显示wela=1;wela=0;delay(200); //调用键盘扫描wela=0;P0=sled_bit_table[6];wela=1;wela=0; //关显示dula=0;P0=a[three];dula=1;dula=0;//数码管位选wela=0;P0=sled_bit_table[2]; //开显示wela=1;wela=0;delay(200); //调用键盘扫描wela=0;P0=sled_bit_table[6];wela=1;wela=0; //关显示dula=0;P0=a[four];dula=1;dula=0;//数码管位选wela=0;P0=sled_bit_table[3]; //开显示wela=1;wela=0;delay(200); //调用键盘扫描wela=0;P0=sled_bit_table[6];wela=1;wela=0; //关显示}/*====分解显示数据=====*/void led_analyze(uint i){i=i%10000;four=i/1000; // 千位three=(i/100)%10; // 百位two=(i%100)/10; // 十位one=(i%100)%10; // 个位}//===================================== ============uchar WheelRight(){LeftCount=0;RightCount++;if (RightCount>=cycle){RightCount=0;return(E_RIGHT);}elsereturn(NULL);}//===================================== ================uchar WheelLeft(){RightCount=0;LeftCount++;if (LeftCount>=cycle){LeftCount=0;return(E_LEFT);}elsereturn(NULL);}//===================================== ============================uchar EncoderProcess(){uchar keytmp;PINA = 1;PINB = 1;WheelNow=WheelNow<<1;if (PINA==1) WheelNow=WheelNow+1; // 读 PINAWheelNow=WheelNow<<1;if (PINB==1) WheelNow=WheelNow+1; // 读 PINBWheelNow=WheelNow & 0x03; // 将 WheelNow 的 2 - 7 位清零,保留 0 - 1 两个位的状态.if (WheelNow==0x00) return(NULL); //当 PINA 和 PINB 都为低电平时退出,低电平区不做处理keytmp=WheelNow;keytmp ^=WheelOld; // 判断新读的数据同旧数据if (keytmp==0) return(NULL); // 新读的数据同旧数据一样时退出.if (WheelOld==0x01 && WheelNow==0x02){ // 是左旋转否WheelOld=WheelNow;return(WheelLeft()); //左旋转}elseif (WheelOld==0x02 && WheelNow==0x01){ // 是右旋转否WheelOld=WheelNow;return(WheelRight()); //右旋转}WheelOld=WheelNow; // 保存当前值return(NULL); // 当 PINA 和 PINB 都为高电平时表示编码器没有动作,退出}//===================================== ===================================== void inc(){wc++;if(wc>9999) wc=0;//如果WG大于9999则将它清零led_analyze(wc);} // 在此处设置断点看 num 加的变化//===================================== ===============================void dec(){wc--;if(wc>9999) wc=9999;led_analyze(wc);} // 在此处设置断点看 num 减的变化//===================================== ====================================== void main(){while (1){switch(EncoderProcess()){case E_RIGHT: inc(); break;case E_LEFT: dec(); break;}display();}}。
//****************************************************************************// // STC12C5A60S2可编程时钟模块////// 说明:STC12C5A60S2单片机有三路可编程时钟输出CLKOUT0/T0/P3.4// CLKOUT1/T1/P3.5、CLKOUT2/P1.0//// 涉及寄存器:AUXR(辅助寄存器)、W AKE_CLKO(时钟与系统掉电唤醒控制寄存器)// BRT(独立波特率发生器定时器寄存器)//// 程序说明:// 本程序可选实现P3.4输出CLKOUT0时钟、P3.5输出CLKOUT1时钟// P1.0输出CLKOUT2时钟//////****************************************************************************/ /#include <STC12C5A60S2.H>#include <intrins.h>//#define Port_BRT //如果想测试独立波特率发生器时钟输出请打开此句//若想测试CLKOUT1和CLKOUT0请注释此句#ifdef Port_BRT /*条件编译独立波特率发生器时钟输出*///*********************************//// CLKOUT2时钟初始化////*********************************//void CLKOUT_init(void){WAKE_CLKO = 0x04; //Bit2-BRTCLKO 允许P1.0配置为独立波特率发生器的时钟输出//BRT工作在1T模式下时的输出频率= Sysclk/(256-BRT)/2//BRT工作在12T模式下时输出频率= Sysclk/12/(256-BRT)/2 AUXR = 0x14; //Bit4-BRTR 允许独立波特率发生器运行//Bit2-BRTx12 BRT工作在1T模式下BRT = 0xff; //更改该寄存器的值可实现对输出的时钟频率进行分频}#else /*条件编译CLKOUT0时钟输出*///*********************************//// CLKOUT0时钟和CLKOUT1初始化////*********************************//void CLKOUT_init(void){WAKE_CLKO = 0x03; //允许将P3.4/T0脚配置为定时器0的时钟输出CLKOUT0//T0工作在1T模式时的输出频率= SYSclk/(256-TH0)/2//T0工作在12T模式时的输出频率= SYSclk/12/(256-TH0)/2//1T指的是每1个时钟加1,是普通C51的12倍//12T指的是每12个时钟加1与普通C51一样//允许将P3.5/T1脚配置为定时器1的时钟输出CLKOUT1,只能工作在定时器模式2下//T1工作在1T模式时的输出频率= SYSclk/(256-TH0)/2//T1工作在12T模式时的输出频率= SYSclk/12/(256-TH0)/2//1T指的是每1个时钟加1,是普通C51的12倍//12T指的是每12个时钟加1与普通C51一样AUXR = 0xc0; //T0定时器速度是普通8051的12倍,即工作在1T模式下//T1定时器速度是普通8051的12倍,即工作在1T模式下TMOD = 0x22; //定时器0工作模式为方式2,自动装载时间常数//定时器1工作模式为方式2,自动装载时间常数TH0 = 0xff; //更改该寄存器的值可实现对输出的时钟频率进行分频TL0 = 0xff;TH1 = 0xff; //更改该寄存器的值可实现对输出的时钟频率进行分频TL1 = 0xff;TR1 = 1;TR0 = 1;}#endif//**********************************//// 主程序////**********************************//void main(){CLKOUT_init();while(1);}//****************************************************************************// // STC12C5A60S2系统时钟模块////// 说明:STC12C5A60S2单片机有两个时钟源,内部R/C振荡时钟和外部晶体时钟// 出厂标准配置是使用外部晶体或时钟////// 涉及寄存器:CLK_DIV(时钟分频寄存器)// 由该寄存器的Bit0-2组合可实现对时钟源进行0、2、4、8、16// 32、64、128分频// //// 程序说明:// 对外部时钟进行分频得到Sysclk,然后经过P1.0的独立波特率// 时钟输出功能Sysclk/2输出时钟频率//****************************************************************************// #include <STC12C5A60S2.h>#include <intrins.h>#define Bus_clk 12 //若要修改系统时钟直接在此处修改//12 为12M 的sysclk//6 为6M 的sysclk//3 为3M 的sysclk//1500 为 1.5M 的sysclk//750 为750kHz 的sysclk//375 为375kHz 的sysclk//187500 为187.5kHz 的sysclk//93750 为93.75kHz 的sysclk//*********************************************//// 系统时钟初始化////*********************************************//void Sysclk_init(void){WAKE_CLKO = 0x04; //配置P1.0口为频率输出AUXR = 0x14; //允许波特率时钟工作//工作模式为1TBRT = 0xff;#if( Bus_clk == 12 )CLK_DIV = 0x00;#elif( Bus_clk == 6 )CLK_DIV = 0x01;#elif( Bus_clk == 3 )CLK_DIV = 0x02;#elif( Bus_clk == 1500 )CLK_DIV = 0x03;#elif( Bus_clk == 750 )CLK_DIV = 0x04;#elif( Bus_clk == 375 )CLK_DIV = 0x05;#elif( Bus_clk == 187500 )CLK_DIV = 0x06;#elif( Bus_clk == 93750 )CLK_DIV = 0x07;#endif}//**********************************************//// 主程序////**********************************************//void main(){Sysclk_init();while(1);}//****************************************************************************// // STC12C5A60S2系统省电模块////// 说明:STC12C5A60S2单片机有三种省电模式以降低功耗.空闲模式,低速模式// 掉电模式////// 涉及寄存器:PCON(电源控制寄存器)// Bit0 - IDL 控制单片机进入IDLE空闲模式// Bit1 - PD 控制单片机进入掉电模式// //// 程序说明:程序实现让单片机先工作一阵子(通过P0^3指示灯显示)// 然后进入掉电状态,利用外部中断0口来唤醒单片机工作// 唤醒后单片机将通过P0^0-3口的灯闪烁显示开始工作////****************************************************************************/ /#include <STC12C5A60S2.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar Power_Down_Flag = 0; //进入掉电状态标志sbit Chip_Start_LED = P0^0; //单片机开始工作指示灯sbit Power_Down_LED_INT0 = P0^1; //INT0口掉电唤醒指示灯sbit N_Power_Down_LED_INT0 = P0^2; //INT0口没有唤醒指示灯sbit Normal_Work_LED = P0^3; //正常工作指示灯sbit Power_Down_Wakeup_INT0= P3^2; //外中断唤醒输入口void Delay_ms( uint time );void Normal_work(void);void Intp_init(void);void After_Powr_Down(void);//***********************************//// 软件延时////***********************************//void Delay_ms( uint time ){uint t; //延时时间= (time*1003+16)us while(time--){for( t = 0; t < 82; t++ );}}//***********************************//// 正常工作指示//***********************************//void Normal_work(void){Normal_Work_LED = 1;Delay_ms(500);Normal_Work_LED = 0;Delay_ms(500);}void After_Power_Down(void){uchar i ;for( i = 0; i < 100; i++ ){P0 = 0x0f;Delay_ms(500);P0 = 0x00;Delay_ms(500);}}//***********************************//// 中断初始化////***********************************//void Intp_init(void){IT0 = 0; //外部中断源0为低电平触发EX0 = 1; //允许外部中断EA = 1; //开总中断}//***********************************//// 主程序////***********************************//void main(){uchar j = 0;uchar wakeup_counter = 0; //记录掉电次数P0 = 0x00;Chip_Start_LED = 1; //单片机开始工作Intp_init(); //外中断0初始化while(1){P2 = wakeup_counter;wakeup_counter++;for( j = 0; j < 250; j++ ){Normal_work(); //系统正常工作指示}Power_Down_Flag = 1; //系统开始进入掉电状态PCON = 0x02;_nop_();_nop_();_nop_();_nop_();After_Power_Down(); //掉电唤醒后}}//**********************************//// 中断服务//**********************************//void INT0_Service(void) interrupt 0{if( Power_Down_Flag ) //掉电唤醒状态指示{Power_Down_Flag = 0;Power_Down_LED_INT0 = 1;while( Power_Down_Wakeup_INT0 == 0 ){_nop_(); //等待高电平}Power_Down_LED_INT0 = 0;}else //未掉电状态{N_Power_Down_LED_INT0 = 1; //不是掉电唤醒指示while( Power_Down_Wakeup_INT0 == 0 ){_nop_();}N_Power_Down_LED_INT0 = 0;}}//****************************************************************************// // STC12C5A60S2 A/D转换模块////// 说明:STC12C5A60S2单片机有8路10位高速AD转换器,P1^0-P1^7//// 涉及寄存器:P1ASF(模拟功能控制寄存器)、ADC_CONTR(ADC控制寄存器)// ADC_RES、ADC_RESL(转换结果寄存器)//// 注意: 1、初次打开内部A/D模拟电源需适当延时等内部模拟电源稳定后,再启动A/D转换// 启动A/D后,在转换结束前不改变任何I/O口的状态,有利于高精度A/D转换// 若能将定时器/串行/中断系统关闭更好。