<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://jackxiang.com/post//</link>
<title><![CDATA[[解决办法]单片机输出PWM波，ds18b20采集温度因PWM的中断导致温度读取有错误的解决办法。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[系统架构与硬件]]></category>
<pubDate>Sat, 25 Aug 2012 15:44:26 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	严泽远&nbsp;&nbsp;10:08:42<br/>我用的是STC12C5628AD<br/><br/>回忆未来-向东-Jàck&nbsp;&nbsp;13:08:22<br/>AT89S52有软件喂狗，但是STC12C5A60S2 单片机有硬件看门狗，用哪个好呢？<br/>张彦欣单片机&nbsp;&nbsp;13:59:27<br/>AT89S52有看门狗？<br/>回忆未来-向东-Jàck&nbsp;&nbsp;14:11:23<br/>STC12C5A60S2&nbsp;&nbsp;这个也需要写代码喂狗？<br/>回忆未来-向东-Jàck&nbsp;&nbsp;14:13:50<br/>STC12C5A60S2&nbsp;&nbsp;这个自己带PWM，我用AT89S52的定时器产生也成，但是好像时序有点问题，如果不关中断的话。所以，STC12C5A60S2&nbsp;&nbsp;感觉要稳定点儿，兄弟怎么看？<br/>张彦欣单片机&nbsp;&nbsp;14:15:19<br/>是的。<br/><br/><br/>用单片机做的温度监控系统，ds18b20采集温度，现在还要输出PWM波频率为100HZ，应该如何实现？求大神指点 <br/>用低定时器中断时不行的，会使ds18b20输出错误，若在ds18b20程序中关中断，pwm波会有断续。<br/>我告诉你为什么：<br/>因为定时器中断是强制性的，一旦计时溢出，无论程序执行到何处都会被暂停，优先去执行中断服务程序。 DS18B20这种对时序有严格要求的单总线通讯，在发送和接收数据时被定时器中断扰乱了时序，所以无法通讯。要解决此问题建议你采用带硬件PWM的MCU，或者将18B20通讯代码放在中断服务程序内部，如果采用后一种方式，PWM计时时间请算上18B20通讯的时间。 <br/><br/>这是一定不行的，定时器写的pwm是会破坏18b20的时序的；<br/>如果时间允许序的话，即pwm高（低）电平时间大于读写18b20的时间；我建议你在每个pwm的高（低）电平的时候进行18b20的操作；<br/>若时间不允许的话，那么只能在定时器中加上18b20的读取时间了，这样将会很麻烦；<br/>以上仅供参考。<br/><br/>稍微高级一点的MCU应该带有PWM寄存器吧,STC也有类似40个引脚的增强型的单片机,如:stc12c5a60s2<br/>http://item.taobao.com/item.htm?spm=a230r.1.10.210&amp;id=9929702075<br/>书：“十五”高等院校规划教材：《增强型8051单片机实用开发技术》<br/>好多地都没有货了，直接购买PDF版本：http://item.taobao.com/item.htm?spm=a230r.1.10.86.WziaXb&amp;id=16258074740<br/>百度文库PWM简单代码：http://wenku.baidu.com/view/f4ef50ec856a561252d36fcb.html<br/>淘宝上有卖开发板的，找到两家便宜的店：<br/>http://item.taobao.com/item.htm?spm=a230r.1.10.208.JW2dkE&amp;id=14811238438&amp;_u=u19u1s735c<br/>对于PWM输出的硬件设计PPT:http://wenku.baidu.com/view/75758588cc22bcd126ff0ca3.html<br/>这样的设计势必要对应程序：http://wenku.baidu.com/view/f02443bd960590c69ec3760f.html<br/>更简单的PWM设置链接：http://wenku.baidu.com/view/f4ef50ec856a561252d36fcb.html<br/>，比如有独立的PWM模块，AT24C04等，和AT系列的单片机不同点在于没有仿真罢了。我遇到这种问题是直接在读取温度时就把中断关闭，不让PWM的中断打扰，读取温度的时间应该很短，影响不大，By:jack<br/>STC12C5A60S2能直接替换STC89C52开发板的上的STC89C52单片机吗？<br/>是40引脚的吧 是的话 应该可以<br/>单片机其他外延模块 LED LCD 蜂鸣器 彩灯之类的 需要单片机来的信号都是TTL信号 单片机的电压变化都是一致的 可以进行替换 芯片只要能实现引脚高低信号电压的一致就没问题<br/>您好：<br/>&nbsp;&nbsp;&nbsp;&nbsp;可以的。STC12C5A60S2和STC89C52引脚兼容，前者只是P0口复用了AD，内部资料多了点。 <br/>http://zhidao.baidu.com/question/206521917.html?fr=qrl&amp;cid=93&amp;index=1<br/><br/>STC12C5A60S2开了两路PWM,还能不能开定时器0中断啊<br/>可以的，STC12C5A60S2的PWM是独立的硬件模块，不耗STC12C5A60S2的指令执行，所以可以开定时器0中断以及处理其它任务<br/>    STC12C5A60S2单片机是一款功能比较强大的单片机，它拥有两个全双工串行通信接口，串口1的功能及操作与传统51单片机串行口相同；特殊的是STC12C5A60S2单片机内部有一个独立波特率发生器，串口1可以使用定时器1作为波特率发生器，也可以使用独立波特率发生器作为波特率发生器；而串口2只能使用独立波特率发生器作为波特率发生器。<br/><br/>一个基础板兼容多种STC和ATMel的单片机板：<br/>http://item.taobao.com/item.htm?spm=a230r.1.10.56.zM593N&amp;id=18138913000<br/>答：支持STC89C52、STC12C5A60S2、AT89C51、AT89C52、AT89S51、AT89S52等最常用的51系列单片机。除此之外，还支持其它40脚的51系列单片机以及ATmega16！STC89C52、STC12C5A60S2可以用串口直接下载程序<br/><br/>DS18B20用N次定时中断读取，比如4MS中断一次，第1次复位18B20， <br/>第2次18B20引脚置高，第3次发出转换命令 搜索器件,并启动，到第40次时再复位18B20,41次引脚置高，42次读取命令，43次读取数据。也就是说读取一次温度，需要中断43次，整个过程都在中断中执行。pwm就可以用中断了，18B20也不会读取错误了。希望对你有帮助。<br/>实时是不行了，这儿可以参考一下时间错位的办法：http://bbs.icbuy.com/thread-57813-1-1.html<br/><br/>STC12C5A60S2单片机双串口，为什么串口1用独立波特率发生器时还要使能定时器（0/1）并允许定时器中断？<br/><br/>串口1波特率可使用定时器1或者独立波特率发生器，使用定时器1时做波特率发生时，你就不能用定时器1了，使用独立波特率发生器时，定时器1得到释放，你可以随时使用；此时你使能定时器（0/1）并允许定时器中断只是为了释放定时器，当然你用不到定时器中断，也可以关掉，对波特率无影响的<br/><br/>STC单片机11.0592晶振实现115200波特率串口通信<br/>在8051系列单片机如：89S51、89C51 这些单片机上，用11.0592M晶振实现115200波特率通信，几乎是不可能的。<br/> <br/>如果换了STC单片机，例如在STC12C5A60S2实现115200的高速通信就相当简单了。<br/>因为，STC12单片机有独立的波特率发生器。<br/> <br/>#include &quot;STC12C5A60S2.H&quot;<br/>#include &quot;stdio.h&quot; <br/>void init_uart()<br/>&#123; <br/>    PCON &amp;= 0x7f;  //波特率不倍速<br/>   SCON = 0x50;  //8位数据,可变波特率<br/>   BRT = 0xFD;      //设定独立波特率发生器重装值<br/>   AUXR &#124;= 0x04;  //独立波特率发生器时钟为Fosc,即1T<br/>   AUXR &#124;= 0x01;  //串口1选择独立波特率发生器为波特率发生器<br/>   AUXR &#124;= 0x10;  //启动独立波特率发生器<br/>&#125;<br/> <br/>char putchar (unsigned char i)<br/>&#123;<br/>    ES     =   0;  //关串口中断<br/>    TI     =   0;  //清零串口发送完成中断请求标志<br/>    SBUF   =   i;<br/>    while(TI ==0); //等待发送完成<br/>    TI     =   0;  //清零串口发送完成中断请求标志<br/>    ES     =   1;  //允许串口中断<br/>    return SBUF;<br/>&#125;<br/> <br/>记得头文件加上  stdio.h，然后在代码里实现 putchar 函数，这样你就可以很方便的用 printf函数进行串口输出了。<br/>例如<br/>    int hh=0,mm=0,ss=0;<br/>    printf(&quot;现在的时间：%d：%d：%d&#92;r&#92;n&quot;, hh,mm,ss);<br/> <br/>是不是串口输出变简单多了。<br/><br/><br/>附录：<br/>下面这个Url的问题应该也是一样的问题，Url：http://bbs.zyxmcu.com/forum.php?mod=viewthread&amp;tid=437&amp;page=1<br/><br/>张大侠，小弟最近遇到一个问题，我做了一个简单的温度控制功能：1602液晶显示温度相关信息，串口向上发送和接受PID，PWM控制，可我用的是T0做的PWM，用T1做的串口波特发生，出现一个问题：我的PWM中断老是进不去，还请张大侠帮忙瞧瞧是肿么了，代码如下：<br/>代码：<br/><textarea name="code" class="C" rows="15" cols="100">
#include&lt;reg52.h&gt;
#include&lt;intrins.h&gt;
#include&lt;stdio.h&gt;
#include &lt;string.h&gt;
sbit PWR_PIN=P3^5;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Tsic506的电源线必须接在上面，否则会出现读取异常。
sbit SIG_PIN=P3^3;
sbit Led=P1^3;
sbit Led0=P1^1;
typedef unsigned int UINT16;
typedef unsigned char UINT8;
#define uchar unsigned char //定义无符号字符
#define uint unsigned int //定义无符号整数
sbit LCD_BLA=P2^7; //液晶模块背光控制
uchar date,Tmp;
uchar idata allCom[13]=&#123;0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00&#125;;
int idata NumBeginFlag = 0;//进入了设置状态
int idata NumOkFlag = 0;//是否可以显示的Flag
int data NumBegin = 0;
uint idata NumId = 21;//传感器的编号
sbit LCD_RS = P2^0 ;
sbit LCD_RW = P2^1 ;
sbit LCD_EN = P2^2 ;
uchar code cdis1[ ] = &#123;&quot;N: P: I: D: &quot;&#125; ;
uchar code cdis2[ ] = &#123;&quot; . C . C&quot;&#125; ;
uchar code cdis3[ ] = &#123;&quot; Tsic506 Error &quot;&#125; ;
uchar code cdis4[ ] = &#123;&quot; Please Check! &quot;&#125; ;
unsigned char send_num[7]=&#123;0,0,0,0,0,0,0&#125;;
uchar kp,ki,kd;
uint t,hightime=0,count=0; //占空比调节参数,默认关闭中断开时的输出。
uint rltemp,settemp=38456;//设置成25.456度
int e1,e2,e3,duk,uk=0;
sbit pwm=P1^2;//这儿设定：P3.6
#define uint unsigned int
sbit scl=P1^3; //24C04 SCL
sbit sda=P1^4; //24C04 SDA
uchar x24C04_read(uchar address); 
void x24C04_write(uchar address,uchar info);
void x24C04_init(); 
void delay1_24C04(uchar x); 
void x24c01_init();
void start();
void stop();
void writex(uchar j);
uchar readx();
void clock();
void WatchDog(void);
void delay1_24C04(uchar x)
&#123;
uint i;
for(i=0;i&lt;x;i++);
&#125;
//-------------------------//
void x24C04_init()
&#123;
scl=1; sda=1; 
&#125;
//-------------------------//
void start()
&#123;
sda=1; scl=1; sda=0; scl=0; 
&#125;
//-------------------------//
void stop()
&#123;
sda=0; scl=1; sda=1; 
&#125;
//-------------------------//
void writex(uchar j)
&#123;
uchar i,temp;
temp=j;
for (i=0;i&lt;8;i++)&#123;
temp=temp&lt;&lt;1; scl=0; sda=CY; scl=1; 
&#125;
scl=0; sda=1; 
&#125;
//-------------------------//
uchar readx()
&#123;
uchar i,j,k=0;
scl=0; sda=1;
for (i=0;i&lt;8;i++)&#123;
scl=1; 
if (sda==1) j=1;
else j=0;
k=(k&lt;&lt;1)&#124;j; scl=0;
&#125;
return(k);
&#125;
//-------------------------//
void clock()
&#123;
uchar i=0;
scl=1; 
while ((sda==1)&amp;&amp;(i&lt;255))i++;
scl=0; 
&#125;
//-------------------------//
uchar x24C04_read(uchar address)
&#123;
uchar i;
start(); writex(0xa0);
clock(); writex(address);
clock(); start();
writex(0xa1); clock();
i=readx(); stop();
delay1_24C04(10);
return(i);
&#125;
//-------------------------//
void x24C04_write(uchar address,uchar info)
&#123;
//EA=0;
start(); writex(0xa0);
clock(); writex(address);
clock(); writex(info);
clock(); stop();
//EA=1;
delay1_24C04(50);
&#125;
void TSIC_ON() &#123;PWR_PIN=1;&#125;
void TSIC_OFF() &#123;PWR_PIN=0;&#125;
void WAIT_60_US()
&#123;
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
&#125;

void TSIC_INIT()
&#123;
PWR_PIN=0; /* power */
SIG_PIN=1; /* signal */
&#125;
UINT16 getTSicTemp (UINT16 *temp_value16)
&#123;
UINT16 temp_value1 = 0;
UINT16 temp_value2 = 0;
UINT8 i;
UINT16 Temperature;
UINT8 parity;
TSIC_ON();
WAIT_60_US();
WAIT_60_US();
while (SIG_PIN == 1);
while (SIG_PIN == 0);
for (i = 0; i &lt; 9; i++)
&#123;
while (SIG_PIN==1);
WAIT_60_US();
if (SIG_PIN==1)
temp_value1 &#124;= 1 &lt;&lt; (8-i);
else
while (SIG_PIN == 0);
&#125;
while (SIG_PIN == 1);
while (SIG_PIN == 0);
for (i = 0; i &lt; 9; i++)
&#123;
while (SIG_PIN==1);
WAIT_60_US();
if (SIG_PIN==1)
temp_value2 &#124;= 1 &lt;&lt; (8-i);
else
while (SIG_PIN == 0);
&#125;
Led=0;
TSIC_OFF();
parity = 0;
for (i = 0; i &lt; 9; i++)
if (temp_value1 &amp; (1 &lt;&lt; i))
parity++;
if (parity % 2)
return 0;
parity = 0;
for (i = 0; i &lt; 9; i++)
if (temp_value2 &amp; (1 &lt;&lt; i))
parity++;
if (parity % 2)
return 0;
temp_value1 &gt;&gt;= 1;
temp_value2 &gt;&gt;= 1;
Temperature = (temp_value1 &lt;&lt; 8) &#124; temp_value2;
*temp_value16 = Temperature;
return 1;
&#125;
unsigned char code mytab[8] = &#123;0x0C,0x12,0x12,0x0C,0x00,0x00,0x00,0x00&#125; ;
#define delayNOP() ; &#123;_nop_() ;_nop_() ;_nop_() ;_nop_() ;&#125; ;
/*******************************************************************/
/* */
/*毫秒延迟函数 */
/* */
/*******************************************************************/
void delay1(int ms)
&#123;
unsigned char y ;
while(ms--)
&#123;
for(y = 0 ; y&lt;250 ; y++)
&#123;
_nop_() ;
_nop_() ;
_nop_() ;
_nop_() ;
&#125;
&#125;
&#125;
/******************************************************************/
/* */
/*检查LCD忙状态 */
/*lcd_busy为1时，忙，等待。lcd-busy为0时,闲，可写指令与数据。 */
/* */
/******************************************************************/
bit lcd_busy()
&#123;
bit result ;
LCD_RS = 0 ;
LCD_RW = 1 ;
LCD_EN = 1 ;
delayNOP() ;
result = (bit)(P0&amp;0x80) ;
LCD_EN = 0 ;
return(result) ;
&#125;
/*******************************************************************/
/* */
/*写指令数据到LCD */
/*RS=L，RW=L，E=高脉冲，D0-D7=指令码。 */
/* */
/*******************************************************************/
void lcd_wcmd(uchar cmd)
&#123;
while(lcd_busy()) ;
LCD_RS = 0 ;
LCD_RW = 0 ;
LCD_EN = 0 ;
_nop_() ;
_nop_() ;
P0 = cmd ;
delayNOP() ;
LCD_EN = 1 ;
delayNOP() ;
LCD_EN = 0 ;
&#125;
/*******************************************************************/
/* */
/*写显示数据到LCD */
/*RS=H，RW=L，E=高脉冲，D0-D7=数据。 */
/* */
/*******************************************************************/
void lcd_wdat(uchar dat)
&#123;
while(lcd_busy()) ;
LCD_RS = 1 ;
LCD_RW = 0 ;
LCD_EN = 0 ;
P0 = dat ;
delayNOP() ;
LCD_EN = 1 ;
delayNOP() ;
LCD_EN = 0 ;
&#125;
/*******************************************************************/
/* */
/* LCD初始化设定 */
/* */
/*******************************************************************/
void lcd_init()
&#123;
delay1(15) ;
lcd_wcmd(0x01) ; //清除LCD的显示内容
lcd_wcmd(0x38) ; //16*2显示，5*7点阵，8位数据
delay1(5) ;
lcd_wcmd(0x38) ;
delay1(5) ;
lcd_wcmd(0x38) ;
delay1(5) ;
lcd_wcmd(0x0c) ; //显示开，关光标
delay1(5) ;
lcd_wcmd(0x06) ; //移动光标
delay1(5) ;
lcd_wcmd(0x01) ; //清除LCD的显示内容
delay1(5) ;
&#125;

/*******************************************************************/
/* */
/* 设定显示位置 */
/* */
/*******************************************************************/
void lcd_pos(uchar pos)
&#123;
lcd_wcmd(pos &#124; 0x80) ; //数据指针=80+地址变量
&#125;
/*******************************************************************/
/* */
/*自定义字符写入CGRAM */
/* */
/*******************************************************************/
void writetab()
&#123;
unsigned char i ;
lcd_wcmd(0x40) ; //写CGRAM
for (i = 0 ; i&lt; 8 ; i++)
lcd_wdat(mytab[ i ]) ;
&#125;
/*******************************************************************/
/* */
/* 数据转换与温度显示 */
/* */
/*******************************************************************/
void Disp_Temperature()
&#123;
if(NumOkFlag == 1)
&#123;//特别注意：if 中已经是ASCII，所以转为10进制时要减去&#039;0&#039;，而在else中,是十进制的，在显示时要加上&#039;0&#039;
//编号赋值
NumId = 0; 
NumId = (allCom[0]-&#039;0&#039;)*10+allCom[1]-&#039;0&#039;;
//p i d赋值
kp = (allCom[2]-&#039;0&#039;)*10+(allCom[3]-&#039;0&#039;);
ki = (allCom[4]-&#039;0&#039;)*10+(allCom[5]-&#039;0&#039;);
kd = (allCom[6]-&#039;0&#039;)*10+(allCom[7]-&#039;0&#039;);
//温度赋值:注意这块传入的值不能溢出，也就是all[8]必须小于等于6，其总的值不能大于：0-65535.如输入：65536就显示00.000了，加1后：00.001类推，一闪是因下面直接显示的原因。后面就到else溢出了。
settemp=(allCom[8]-&#039;0&#039;)*10000+(allCom[9]-&#039;0&#039;)*1000+(allCom[10]-&#039;0&#039;)*100+(allCom[11]-&#039;0&#039;)*10+(allCom[12]-&#039;0&#039;);

//开始存入C24C04
x24C04_write(&#039;0&#039;,NumId);//第0单元写入编号数据
delay1(50);
x24C04_write(&#039;1&#039;,kp);//第1单元写入kp数据
delay1(50);
x24C04_write(&#039;2&#039;,ki);//第2单元写入ki数据
delay1(50);
x24C04_write(&#039;3&#039;,kd);//第3单元写入kd数据
delay1(50);
//5位温度值写入
Tmp = (settemp/10000%10);
x24C04_write(&#039;4&#039;,Tmp);
delay1(50);
Tmp = (settemp/1000%10);
x24C04_write(&#039;5&#039;,Tmp);
delay1(50);
Tmp = (settemp/100%10);
x24C04_write(&#039;6&#039;,Tmp);
delay1(50);
Tmp = (settemp/10%10); 
x24C04_write(&#039;7&#039;,Tmp);
delay1(50);
Tmp = settemp%10; 
x24C04_write(&#039;8&#039;,Tmp);
delay1(50);

//编号显示
lcd_pos(0x02) ;
lcd_wdat(allCom[0]) ; //编号十位显示
lcd_pos(0x03) ;
lcd_wdat(allCom[1]) ; //编号个位显示

//显示P
lcd_pos(0x06) ;
lcd_wdat(allCom[2]) ; //温度P参数 
lcd_pos(0x07) ;
lcd_wdat(allCom[3]) ; //温度P参数
//显示I
lcd_pos(0x0A) ;
lcd_wdat(allCom[4]) ; //温度I参数 
lcd_pos(0x0B) ;
lcd_wdat(allCom[5]) ; //温度I参数 
//显示D
lcd_pos(0x0E) ;
lcd_wdat(allCom[6]) ; //温度D参数 
lcd_pos(0x0F) ;
lcd_wdat(allCom[7]) ; //温度D参数 
//显示设定温度
lcd_pos(0x40) ;
lcd_wdat(allCom[8]) ; //温度显示 
lcd_pos(0x41) ;
lcd_wdat(allCom[9]) ; //温度显示 
lcd_pos(0x43) ;
lcd_wdat(allCom[10]) ; //温度显示 
lcd_pos(0x44) ;
lcd_wdat(allCom[11]) ; //温度显示 
lcd_pos(0x45) ;
lcd_wdat(allCom[12]) ; //温度显示 
NumOkFlag = 0;//置位
&#125;else
&#123;

uchar tmpNumId=0,tmpkp=0,tmpki=0,tmpkd=0,tmpsettemp4=0,tmpsettemp5=0,tmpsettemp6=0,tmpsettemp7=0,tmpsettemp8=0;//读C24C04里的数据
tmpNumId = x24C04_read(&#039;0&#039;);
tmpkp = x24C04_read(&#039;1&#039;);
tmpki = x24C04_read(&#039;2&#039;);
tmpkd = x24C04_read(&#039;3&#039;);
tmpsettemp4 = x24C04_read(&#039;4&#039;);
tmpsettemp5 = x24C04_read(&#039;5&#039;);
tmpsettemp6 = x24C04_read(&#039;6&#039;);
tmpsettemp7 = x24C04_read(&#039;7&#039;);
tmpsettemp8 = x24C04_read(&#039;8&#039;);
if(tmpNumId != 0xff)
&#123;
NumId = tmpNumId;
&#125;
if(tmpkp != 0xff)
&#123;
kp = tmpkp;
&#125;
if(tmpki != 0xff)
&#123;
ki = tmpki;
&#125;
if(tmpkd != 0xff)
&#123;
kd = tmpkd;
&#125;
if((tmpsettemp5 !=0xff)&amp;&amp;(tmpsettemp6 !=0xff)&amp;&amp;(tmpsettemp7 !=0xff)&amp;&amp;(tmpsettemp8 !=0xff))
&#123;
settemp=(tmpsettemp4)*10000+(tmpsettemp5)*1000+(tmpsettemp6)*100+(tmpsettemp7)*10+(tmpsettemp8);
&#125;

//正常时的显示，主要是防止溢出或者异常
//编号显示
lcd_pos(0x02) ;
Tmp = NumId/10;
lcd_wdat(Tmp+&#039;0&#039;) ; //编号十位显示
lcd_pos(0x03) ;
Tmp = NumId%10;
lcd_wdat(Tmp+&#039;0&#039;) ; //编号个位显示


//显示P值
lcd_pos(0x06) ;
Tmp = kp/10;
lcd_wdat(Tmp+&#039;0&#039;) ; //温度P参数 
lcd_pos(0x07) ;
Tmp = kp%10;
lcd_wdat(Tmp+&#039;0&#039;) ; //温度P参数
//显示I值
lcd_pos(0x0A) ;
Tmp = ki/10;
lcd_wdat(Tmp+&#039;0&#039;) ; //温度I参数 
lcd_pos(0x0B) ;
Tmp = ki%10;
lcd_wdat(Tmp+&#039;0&#039;) ; //温度I参数 
//显示D值
lcd_pos(0x0E) ;
Tmp = (uchar*)(kd/10);
lcd_wdat(Tmp+&#039;0&#039;) ; //温度D参数 
lcd_pos(0x0F) ;
Tmp = (uchar*)(kd%10);
lcd_wdat(Tmp+&#039;0&#039;) ; //温度D参数 
//显示设定温度，这儿因扩大了1000倍方便PID。
lcd_pos(0x40) ;
Tmp = (settemp/10000%10);
lcd_wdat(Tmp+&#039;0&#039;) ; //温度十位显示 
lcd_pos(0x41) ;
Tmp = (settemp/1000%10);
lcd_wdat(Tmp+&#039;0&#039;) ; //温度个位显示 
lcd_pos(0x43) ;
Tmp = (settemp/100%10);
lcd_wdat(Tmp+&#039;0&#039;) ; //温度小数后一位显示 
lcd_pos(0x44) ;
Tmp = (settemp/10%10); //温度小数后两位显示 
lcd_wdat(Tmp+&#039;0&#039;) ; 
lcd_pos(0x45) ;
Tmp = settemp%10; //温度的度符号显示 
lcd_wdat(Tmp+&#039;0&#039;) ; 
lcd_pos(0x46) ; //温度符号
lcd_wdat(0x00) ;
&#125;
//Tsic506传感器的实时温度值显示
lcd_pos(0x48) ;
lcd_wdat(send_num[0]) ; //十位数显示

lcd_pos(0x49) ;
lcd_wdat(send_num[1]) ; //个位数显示
//有小数点了，注释掉。
/*
lcd_pos(0x4a) ;
lcd_wdat(send_num[2]) ; //小数点显示
*/
lcd_pos(0x4b) ;
lcd_wdat(send_num[3]) ; //小数第一位显示

lcd_pos(0x4c) ;
lcd_wdat(send_num[4]) ; //小数第二位数显示

lcd_pos(0x4d) ;
lcd_wdat(send_num[5]) ; //小数第三位数显示

lcd_pos(0x4E) ; //温度符号
lcd_wdat(0x00) ;
&#125;

/*******************************************************************/
/* */
/* Tsic506 OK 显示菜单 */
/* */
/*******************************************************************/
void Ok_Menu ()
&#123;
uchar m ;
lcd_init() ; //初始化LCD
lcd_pos(0) ; //设置显示位置为第一行的第1个字符
m = 0 ;
while(cdis1[m] != &#039;&#92;0&#039;)
&#123; //显示字符
lcd_wdat(cdis1[m]) ;
m++ ;
&#125;
lcd_pos(0x40) ; //设置显示位置为第二行第1个字符
m = 0 ;
while(cdis2[m] != &#039;&#92;0&#039;)
&#123;
lcd_wdat(cdis2[m]) ; //显示字符
m++ ;
&#125;
writetab() ; //自定义字符写入CGRAM
delay1(5) ;
lcd_pos(0x4d) ;
lcd_wdat(0x00) ; //显示自定义字符
&#125;

/******************************
PID算法系数装载
*******************************/
void Pid_init()
&#123;
hightime= 0;//全速，和占空比有关
e1 = 0;//PID工式里有关系
e2 = 0;//PID工式里有关系
e3 = 0;//PID工式里有关系
kp = 10;//比例值：加热速率快 三个值参考来源：http://wenku.baidu.com/view/92dfa0000740be1e650e9ae4.html
ki = 5;//积分值：调节
kd = 5;//微分值 ：调节 
&#125;
/******************************
温度比较 PID算法
*******************************/
void pid_ys()
&#123;
if(rltemp&lt;settemp) // 如果实际温度小于设定值
&#123;
if(settemp-rltemp&gt;1600) // 如果相差1.6度
&#123;
hightime=100; //全速加热
&#125;
else //否则运行PID算法进行平滑加热
&#123;
e1 = settemp-rltemp;
duk=(kp*(e1-e2)+ki*e1+kd*(e1-e2*2+e3))/1000;
uk = uk+duk;
if(uk&gt;100)
uk = 100;
else if(uk&lt;-100)
uk = -100;
if(uk&lt;0)
&#123;
hightime=-uk;
&#125;
else
&#123;
hightime=uk;
&#125;
e3 = e2;
e2 = e1;
&#125;
&#125;
if(rltemp&gt;=settemp) // 如果实际温度大于设定值
&#123;
hightime = 0; //停止加热
&#125;else //其他情况运行PID算法，但参数与前面的刚好相反
&#123;
e1 = rltemp-settemp;
duk=(kp*(e1-e2)+ki*e1+kd*(e1-e2*2+e3))/1000;
uk = uk+duk;
if(uk&gt;100)
uk = 100;
else if(uk&lt;-100)
uk = -100;
if(uk&lt;0)
&#123;
hightime=100-(-uk);
&#125;
else
&#123;
hightime=100-uk;
&#125;
e3 = e2;
e2 = e1;
&#125;
&#125;
main()
&#123;
float Temp_float;

unsigned char send_num_com[23]=&#123;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#125;;
unsigned int i=0;
UINT16 temp_value; 

/*以下我的代码PWM用Timer0，波特率用Timer1，timer1() interrupt 3中的3要改成1*/
EA = 1; //开总中断
ET0 = 1; //Timer0中断允许
ET1 = 1; //Timer1中断允许
ES = 1; //打开串口中断
TMOD = 0x21; //定时器工作方式设置，Timer0 16位模式，Timer1 8位自动装载
TH0 = 0X3C; //Timer0定时高位
TL0 = 0XB0; //Timer0定时低位，用于输出PWM
TL1 = 0xfd; //
TH1 = 0xfd; //8位自动装载，用于产生波特率:波特率for 9600 baud @ 11.0592MHz
SCON = 0x50; //串口工作方式设置
PCON = 0x00; //波特率倍增设置
TI = 0; // 清0发送中断标志
TR0 = 1; //打开Timer0
TR1 = 1; //打开Timer1

WatchDog();//初始化看门狗
x24C04_init();//IIC函数读取,温度设定初始化从IIC读取
Pid_init(); // PID初始化 
LCD_BLA=0; //开启液晶模块背光
pwm = 1;//默认输出高电平，关掉PWM的输出。
Ok_Menu();
TSIC_OFF();
Disp_Temperature() ;
TSIC_ON();
TSIC_INIT();//初始化Tsic506信号线
while(1)
&#123; 
WatchDog();
getTempAgain://防止获取失败，用Goto语句。
if (getTSicTemp(&amp;temp_value))
&#123; 
Temp_float = ((float)temp_value / 2047 * 70) - 10;
sprintf(send_num, &quot;%06.3f&quot;, Temp_float);//如:26.123
sprintf(send_num_com, &quot;@00000000#000000#%06.3f&quot;,Temp_float);//把这个带编号的数发送到串口
send_num_com[1] = NumId/10+0x30;
send_num_com[2] = NumId%10+0x30;
send_num_com[3] = (int)kp/10+0x30;
send_num_com[4] = (int)kp%10+0x30;
send_num_com[5] = (int)ki/10+0x30;
send_num_com[6] = (int)ki%10+0x30;
send_num_com[7] = (int)kd/10+0x30;
send_num_com[8] = (int)kd%10+0x30;
send_num_com[10] = (int)(settemp/10000%10)+0x30;
send_num_com[11] = (int)(settemp/1000%10)+0x30;
send_num_com[12] = &#039;.&#039;;
send_num_com[13] = (int)(settemp/100%10)+0x30;
send_num_com[14] = (int)(settemp/10%10)+0x30;
send_num_com[15] = (int)(settemp%10)+0x30;
&#125;else
&#123;
goto getTempAgain;
&#125;

for(i=0;i&lt; strlen(send_num_com);i++)
&#123;
SBUF = send_num_com;
while(!TI);
TI = 0;
WatchDog();
&#125;

Disp_Temperature() ;
rltemp = Temp_float*1000; //给PID算法装载实际值，这个值在38上下一度，因此小于65532，是因为单片机适合整数计算，所以：X1000
pid_ys();//运行温度比较 PID算法
rltemp = 0;//清零
//设置温控编号，Pid调节值和需要维持并稳定的温度
if(RI==1) //检测是否有数据接收 
&#123;
date=SBUF; //接收数据
RI=0;
if(date == &#039;s&#039;)
&#123;//设定温度及PID值
NumBeginFlag = 1;//已经进入设置标志位
NumBegin = 0;//开始从0到12
NumOkFlag = 0;
&#125;else if(date == &#039;c&#039;)
&#123;//设定时出错，取消及完成
NumBeginFlag = 0;//重新设定标志位清0
NumBegin = 0;//开始从0到12 ,清0 
NumOkFlag = 0;//设置完成
&#125;else
&#123; 
if(NumBeginFlag == 1)
&#123;
allCom[NumBegin] = date;
NumBegin++;

if(NumBegin == 13)
&#123;//最后一次记数数组编号为12,但经测试把握是13 
NumOkFlag = 1;//确定后显示
&#125;
&#125;
&#125;
&#125;
&#125;
TSIC_OFF();//Tsic506读取结束，等待下一次读取。
&#125;
//void timer1() interrupt 3 &#123;&#125;
/******************************
PWM波输出的定时中断
*******************************/
void timer0() interrupt 1
&#123;

if(++count&lt;=(hightime))
pwm=0;//低电平接通电源：作者QQ聊天时确认。
else if(count&lt;=100)
&#123;
pwm=1;
&#125;
else
count=0; 
TH0=0x3c;
TL0=0xb0; 
&#125;

void WatchDog(void)
&#123;
WDTRST &#124;=0x1E;
WDTRST &#124;=0xE1;
&#125;
</textarea><br/><br/><br/>这位王建军兄弟的代码采用了在读取温度时是ADC0809采集数据，IN4148为温度传感器，值得学习参考：<br/><br/><textarea name="code" class="C" rows="15" cols="100">
/*=============================================
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CopyLeft(CL) FORVERE Wjj
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;All rights NOT reserved
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 版权所无，翻版不究，但请保留此处信息
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://blog.sina.com.cn/u/2150397142&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; any problem or suggestion mail to:&nbsp;&nbsp;15258297408@163.com
*******************************************/
*文件名：PID_control
*文件说明:PID温控源代码，采用PID算法处理的温控模拟系统 ，ADC0809采集数据，IN4148为温度传感器
*版本:&nbsp;&nbsp;The final version
*芯片:&nbsp;&nbsp;STC89C52RC
*晶振:&nbsp;&nbsp;(外)内部12MHz晶振
*作者:&nbsp;&nbsp;Wang Jian Jun
*日期:&nbsp;&nbsp;2010年5月27日&nbsp;&nbsp;
*编译环境: keil3+proteus7 
*结果：&nbsp;&nbsp;实物测试通过，温度维持在33℃-35℃ 
*说明:&nbsp;&nbsp; 采用PID算法处理的温控模拟系统 ，ADC0809采集数据，IN4148为温度传感器，LCD显示

========================================*/

#include&lt;reg51.h&gt; 
#include&lt;intrins.h&gt; 
#define N0 40536
#define nop() _nop_()
#define uchar unsigned char
#define uint unsigned int

/*程序中变量 数组定义*/
uchar idata table[]=&#123;&quot;Real-time Temp:&quot;&#125;;//第一行显示&quot;Real-time Temp:&quot;
uchar idata table1[5];
uchar data1,kp,ki,kd;&nbsp;&nbsp;&nbsp;&nbsp;
uint t,hightime,count;&nbsp;&nbsp; //占空比调节参数
uint rltemp,settemp=350;
int e1,e2,e3,duk,uk;

/*引脚定义*/
sbit EOC=P2^6;
sbit OE=P2^5;
sbit START=P2^7;
sbit lcden=P3^2;
sbit lcdrw=P3^1;
sbit lcdrs=P3^0;
sbit pwm=P3^3;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 延时子程序
*******************************/
void delay(uint z)
&#123;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;uint x,y;
&nbsp;&nbsp;for(x=z;x&gt;0;x--)
&nbsp;&nbsp;for(y=29;y&gt;0;y--);
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD忙检测
*******************************/
bit lcd_busy()
&#123;
&nbsp;&nbsp;bit result;
&nbsp;&nbsp;lcdrw = 1;
&nbsp;&nbsp;lcdrs = 0;
&nbsp;&nbsp;lcden = 1;
&nbsp;&nbsp;nop();nop();nop();nop();
&nbsp;&nbsp;result = (bit)(P0&amp;0x80);
&nbsp;&nbsp;lcden = 0;
&nbsp;&nbsp;return(result);
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCD写命令子程序
*******************************/
void write_com(uchar com)
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;while(lcd_busy());//忙等待
&nbsp;&nbsp;lcdrs = 0;
&nbsp;&nbsp;lcdrw = 0;
&nbsp;&nbsp;P1 = com;
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;lcden = 1;
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;lcden = 0;
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCD写数据子程序
*******************************/
void write_data(uchar date)
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;while(lcd_busy()); //忙等待
&nbsp;&nbsp;lcdrs = 1;
&nbsp;&nbsp;lcdrw = 0;
&nbsp;&nbsp;P1=date;
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;lcden = 1;
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;lcden = 0;
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD初始化
*******************************/
void lcd_init()
&#123;
&nbsp;&nbsp;lcden = 0;
&nbsp;&nbsp;write_com(0x38);
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;write_com(0x0f);
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;write_com(0x06);
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;write_com(0x01);
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;write_com(0x80);
&nbsp;&nbsp;delay(5);
&nbsp;&nbsp;write_com(0x01);
&#125; 

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;定时器初始化
*******************************/
void time_init()&nbsp;&nbsp;&nbsp;&nbsp;
&#123;
&nbsp;&nbsp;EA = 1;
&nbsp;&nbsp;ET0 = 1;
&nbsp;&nbsp;ET1 = 1;
&nbsp;&nbsp;TR0 = 1;
&nbsp;&nbsp;TR1 = 1;
&nbsp;&nbsp;TMOD = 0x11;
&nbsp;&nbsp;&nbsp;&nbsp;TH0 = N0/256;
&nbsp;&nbsp;&nbsp;&nbsp;TL0 = N0%256;
&nbsp;&nbsp;TH1 = 0X3C;
&nbsp;&nbsp;TL1 = 0XB0;&nbsp;&nbsp;
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp; PID算法系数装载
*******************************/
void Pid_init()
&#123;
&nbsp;&nbsp;hightime= 0;
&nbsp;&nbsp;e1 = 0;
&nbsp;&nbsp;e2 = 0;
&nbsp;&nbsp;e3 = 0;
&nbsp;&nbsp;kp = 10;
&nbsp;&nbsp;ki = 5;
&nbsp;&nbsp;kd = 5;&nbsp;&nbsp;
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp; 温度比较&nbsp;&nbsp;PID算法
*******************************/
void pid_ys()
&#123;
&nbsp;&nbsp;if(rltemp&lt;settemp)&nbsp;&nbsp; //&nbsp;&nbsp;如果实际温度小于设定值
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;if(settemp-rltemp&gt;20) // 如果相差2度
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hightime=100;&nbsp;&nbsp;&nbsp;&nbsp;//全速加热
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //否则运行PID算法进行平滑加热
&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1 = settemp-rltemp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duk=(kp*(e1-e2)+ki*e1+kd*(e1-e2*2+e3))/10;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uk = uk+duk;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(uk&gt;100)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uk = 100;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if(uk&lt;-100)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uk = -100;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(uk&lt;0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hightime=-uk;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hightime=uk;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e3 = e2;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e2 = e1;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;
&nbsp;&nbsp;if(rltemp&gt;=settemp)&nbsp;&nbsp;//&nbsp;&nbsp;如果实际温度大于设定值
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;if(rltemp-settemp&gt;0)&nbsp;&nbsp;//只要实际温度与设定值有偏差
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hightime=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//停止加热
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//其他情况运行PID算法，但参数与前面的刚好相反
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1 = rltemp-settemp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duk=(kp*(e1-e2)+ki*e1+kd*(e1-e2*2+e3))/10;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uk = uk+duk;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(uk&gt;100)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uk = 100;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if(uk&lt;-100)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uk = -100;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(uk&lt;0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hightime=100-(-uk);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hightime=100-uk;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e3 = e2;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e2 = e1;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&#125;
&nbsp;&nbsp;
&#125;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 主函数
*******************************/
void main()
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;uint i;
&nbsp;&nbsp;time_init();//定时器初始化
&nbsp;&nbsp;Pid_init();&nbsp;&nbsp;// PID初始化
&nbsp;&nbsp;lcd_init();&nbsp;&nbsp;// LCD初始化
&nbsp;&nbsp;table1[5]=0x43;&nbsp;&nbsp;
&nbsp;&nbsp;table1[4]=0xdf;
&nbsp;&nbsp;table1[2]=0x2e;&nbsp;&nbsp;//小数点 摄氏度符号ASCII码
&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i&lt;15;i++)&nbsp;&nbsp;//带循环第一行显示&quot;Real-time Temp:&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;write_data(table[i]);
&nbsp;&nbsp;&nbsp;&nbsp;delay(20);
&nbsp;&nbsp;&#125;
&nbsp;&nbsp;while(1)
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t=data1*196/100;
&nbsp;&nbsp;&nbsp;&nbsp;table1[3]=(t%100)%10+0x30;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;table1[1]=(t%100)/10+0x30;
&nbsp;&nbsp;&nbsp;&nbsp;table1[0]=t/100+0x30; //以上温度数据转化
&nbsp;&nbsp;&nbsp;&nbsp;rltemp = t;&nbsp;&nbsp; //给PID算法装载实际值
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write_com(0x80+0x45);//写LCD第二行的初地址
&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i&lt;5;i++) //该循环显示温度值
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write_data(table1[i]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delay(20);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;pid_ys();//运行温度比较 PID算法
&nbsp;&nbsp;&#125;
&#125;

/****************************** 
&nbsp;&nbsp; 温度采集转换的定时中断
&nbsp;&nbsp;&nbsp;&nbsp; 0.5s刷新一次数据
*******************************/
void&nbsp;&nbsp;timer0() interrupt 1
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;uint j;
&nbsp;&nbsp;j++;
&nbsp;&nbsp;if(j==20)
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;OE = 0;
&nbsp;&nbsp;&nbsp;&nbsp;START = 0;
&nbsp;&nbsp;&nbsp;&nbsp;_nop_();
&nbsp;&nbsp;&nbsp;&nbsp;START = 1;
&nbsp;&nbsp;&nbsp;&nbsp;_nop_();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;START = 0;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;while(EOC==0);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;OE = 1;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;_nop_();
&nbsp;&nbsp;&nbsp;&nbsp;data1 = P0;
&nbsp;&nbsp;&nbsp;&nbsp;_nop_();
&nbsp;&nbsp;&nbsp;&nbsp;OE = 0; 
&nbsp;&nbsp;&nbsp;&nbsp;j = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;TH0=N0/256;
&nbsp;&nbsp;&nbsp;&nbsp;TL0=N0%256;
&#125;&nbsp;&nbsp;

/****************************** 
&nbsp;&nbsp;&nbsp;&nbsp; PWM波输出的定时中断
*******************************/
void&nbsp;&nbsp;timer1() interrupt 3
&#123; 
&nbsp;&nbsp;if(++count&lt;=(hightime)) 
&nbsp;&nbsp;&nbsp;&nbsp;pwm=0; 
&nbsp;&nbsp;else if(count&lt;=100) 
&nbsp;&nbsp;&#123; 
&nbsp;&nbsp;&nbsp;&nbsp;pwm=1; 
&nbsp;&nbsp;&#125; 
&nbsp;&nbsp;else 
&nbsp;&nbsp;&nbsp;&nbsp;count=0; 
&nbsp;&nbsp;TH1=0x3c; 
&nbsp;&nbsp;TL1=0xb0; 
&#125; 



</textarea><br/><br/><br/>STC单片机最新型号——STC12C5A60S2<br/><br/><br/>STC12C5A60S2/AD/PWM系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机，是高速/低功耗/超强抗干扰的新一代8051单片机，指令代码完全兼容传统8051,但速度快8-12倍。内部集成MAX810专用复位电路,2路PWM,8路高速10位A/D转换(250K/S),针对电机控制，强干扰场合。<br/>1.增强型8051 CPU，1T，单时钟/机器周期，指令代码完全兼容传统8051；<br/>2.工作电压：STC12C5A60S2系列工作电压：5.5V-3.3V（5V单片机）STC12LE5A60S2系列工作电压：3.6V-2.2V（3V单片机）；<br/>3.工作频率范围：0 - 35MHz，相当于普通8051的 0～420MHz；<br/>4.用户应用程序空间8K /16K / 20K / 32K / 40K / 48K / 52K / 60K / 62K字节；<br/>5.片上集成1280字节RAM；<br/>6.通用I/O口（36/40/44个），复位后为：准双向口/弱上拉（普通8051传统I/O口），可设置成四种模式：准双向口/弱上拉，推挽/强上拉，仅为输入/高阻，开漏，每个I/O口驱动能力均可达到20mA，但整个芯片最大不要超过55Ma；<br/>7. ISP（在系统可编程）/IAP（在应用可编程），无需专用编程器，无需专用仿真器  可通过串口（P3.0/P3.1）直接下载用户程序，数秒即可完成一片；<br/>8.有EEPROM功能(STC12C5A62S2/AD/PWM无内部EEPROM)；<br/>9. 看门狗；<br/>10.内部集成MAX810专用复位电路（外部晶体12M以下时，复位脚可直接1K电阻到地）；<br/>11.外部掉电检测电路:在P4.6口有一个低压门槛比较器，5V单片机为1.32V，误差为+/-5%,3.3V单片机为1.30V，误差为+/-3%；<br/>12.时钟源：外部高精度晶体/时钟，内部R/C振荡器(温漂为+/-5%到+/-10%以内) 1用户在下载用户程序时，可选择是使用内部R/C振荡器还是外部晶体/时钟，常温下内部R/C振荡器频率为：5.0V单片机为：11MHz～15.5MHz，3.3V单片机为：8MHz～12MHz，精度要求不高时，可选择使用内部时钟，但因为有制造误差和温漂，以实际测试为准；<br/>13.共4个16位定时器   两个与传统8051兼容的定时器/计数器,16位定时器T0和T1，没有定时器2，但有独立波特率发生器   做串行通讯的波特率发生器   再加上2路PCA模块可再实现2个16位定时器；<br/>14. 2个时钟输出口，可由T0的溢出在P3.4/T0输出时钟，可由T1的溢出在P3.5/T1输出时钟；<br/>15.外部中断I/O口7路,传统的下降沿中断或低电平触发中断,并新增支持上升沿中断的PCA模块， Power Down模式可由外部中断唤醒，INT0/P3.2,INT1/P3.3,T0/P3.4, T1/P3.5, RxD/P3.0,CCP0/P1.3(也可通过寄存器设置到P4.2 ), CCP1/P1.4 (也可通过寄存器设置到P4.3)；<br/>16. PWM(2路）/PCA（可编程计数器阵列,2路）：<br/>——也可用来当2路D/A使用<br/>——也可用来再实现2个定时器<br/>——也可用来再实现2个外部中断(上升沿中断/下降沿中断均可分别或同时支持)；<br/>17.A/D转换, 10位精度ADC，共8路，转换速度可达250K/S(每秒钟25万次)18.通用全双工异步串行口(UART)，由于STC12系列是高速的8051，可再用定时器或PCA软件实现多串口；<br/>19. STC12C5A60S2系列有双串口，后缀有S2标志的才有双串口，RxD2/P1.2(可通过寄存器设置到P4.2)，TxD2/P1.3(可通过寄存器设置到P4.3)；<br/>20.工作温度范围：-40 - +85℃(工业级) / 0 - 75℃(商业级)21.封装：PDIP-40,LQFP-44,LQFP-48  I/O口不够时，可用2到3根普通I/O口线外接  74HC164/165/595（均可级联）来扩展I/O口,  还可用A/D做按键扫描来节省I/O口，或用双CPU,三线通信，还多了串口。<br/> <br/>数据手册下载：STC12C5A60S2&nbsp;&nbsp;http://course.zjnu.cn/dpjyl/upload/2010_04/10041015327108.pdf<br/><br/>资料整理：余水宝、陈希<br/><br/> <br/><br/><br/>STC12C5A60S2可调节PWM输出 （按键或串口调节）:http://www.ndiy.cn/thread-6455-1-1.html<br/><textarea name="code" class="C" rows="15" cols="100">
#include&lt;reg52.h&gt;//定义头文件
#include &lt;math.h&gt;
#define uchar unsigned char//宏定义数类型
#define uint unsigned int
sbit sw0=P2^0;
sbit sw1=P2^1;
uchar pwm=0xcc;
uchar rx[8]=&#123;0&#125;;
uchar i,ii;
void DelayMs(uchar ms) //在11.0592M晶振下，stc10f系列（单周期指令）的ms级延时
&#123;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
uint i;
while(ms--)
&#123;
&nbsp;&nbsp; for(i = 0; i &lt; 850; i++);
&#125;
&#125;
//////////////////////////////////////////////////////////
void serial_port_one_initial(void)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //串口1初始化
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SCON=0x50;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TMOD=0x21;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //0010 0000&nbsp;&nbsp;定时器1设置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SOMD=0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 12T模式
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TH1=0xFD;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TL1=0xFD;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TR1=1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //开定时器&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ES=1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EA=1;
&nbsp;&nbsp;&nbsp;&nbsp;PS=1;&nbsp;&nbsp;&nbsp;&nbsp;//串口优先级
&#125;
//////////////////////////////////////////////////////////
void send_UART_One(uchar uat)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//串口1发送程序
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ES=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TI=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SBUF=uat;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(TI==0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TI=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ES=1;
&#125;
//////////////////////////////////////////////////
void PWM_int()
&#123; 
CCON=0;
CL=0;
CH=0;
CMOD=0X04;
CCAP0L = pwm;
CCAP0H = pwm;&nbsp;&nbsp; //模块0初始输出 占空因数为80%
CCAPM0 = 0X42;; //模块0设置为8位PWM输出，无中断
CR=1; //PCA计数器开始计数
&#125;
void intimer() //定时器0工作在1t模式提供PWM时钟频率定时器1用于定时刷新占空比
&#123;
TH0=(65536-67)/256;
TL0=(65536-67)%256;
TMOD=0x02;
AUXR=0x00;
ET0=1;
TR0=1;
// EA=1;
&#125;
void KEY_CAN()
&#123;
&nbsp;&nbsp;if(sw0==0)
&#123;
&nbsp;&nbsp;DelayMs(10);
&nbsp;&nbsp;if(sw0==0)
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp; while(!sw0);//松手检测
&nbsp;&nbsp;&nbsp;&nbsp; pwm=pwm+5;
&nbsp;&nbsp;&nbsp;&nbsp; CCAP0L = pwm;
&nbsp;&nbsp;&nbsp;&nbsp; CCAP0H = pwm; 
&nbsp;&nbsp;&#125;
&#125;
&nbsp;&nbsp;if(sw1==0)
&#123;
&nbsp;&nbsp;DelayMs(10);
&nbsp;&nbsp;if(sw1==0)
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp; while(!sw1);//松手检测
&nbsp;&nbsp;&nbsp;&nbsp; pwm=pwm-5;
&nbsp;&nbsp;&nbsp;&nbsp; CCAP0L = pwm;
&nbsp;&nbsp;&nbsp;&nbsp; CCAP0H = pwm; 
&nbsp;&nbsp;&#125;
&#125;
&#125;
void main(void)//主函数
&#123;
PWM_int();
intimer();
serial_port_one_initial();
while(1)
&#123;
&nbsp;&nbsp;KEY_CAN();
&#125;
&#125;

void UART_Interrupt_Receive(void) interrupt 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //串口1中断接收程序
&#123;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; RI=0;
&nbsp;&nbsp; rx[i]=SBUF; //将数据放入rx[];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp; if(rx[0]==0x01)//判断接收
&nbsp;&nbsp; &#123;
&nbsp;&nbsp;&nbsp;&nbsp; i++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //接收数据字节数
&nbsp;&nbsp;&nbsp;&nbsp; if(i&gt;5) 
&nbsp;&nbsp;&nbsp;&nbsp; &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uchar jiaoyan;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(ii=0;ii&lt;4;ii++)//和校验
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jiaoyan+=rx[ii];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((rx[0]==0x01)&amp;(rx[5]==0x16)&amp;(rx[4]==jiaoyan))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(rx[1]==0x09)//写转数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#123; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pwm=rx[2];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CCAP0L = pwm;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CCAP0H = pwm; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rx[1]=rx[1]+0x10; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(ii=0;ii&lt;6;ii++)&nbsp;&nbsp; //响应返回
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send_UART_One(rx[ii]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jiaoyan=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i=0;
&nbsp;&nbsp;&nbsp;&nbsp; &#125;
&nbsp;&nbsp; &#125;
&nbsp;&nbsp; else
&nbsp;&nbsp;&nbsp;&nbsp; i=0;&nbsp;&nbsp; //接收数据串字节数清零
&#125;

void exter0() interrupt 1
&#123;
TH0=(65536-67)/256;
TL0=(65536-67)%256;
&#125;

</textarea><br/><br/><br/><br/><br/><br/>Stc PWM&nbsp;&nbsp;设置方法：<br/><textarea name="code" class="php" rows="15" cols="100">
网上看了STc12C5A60S2看了一些资料，自己也找了一些程序，但是对于一个接触单片机3个月，程序只会IF来，IF去的新手，压力还是巨大的~


STc12C5A60S2内部自带PWM，而且能定义到传说中的P4口，请问，这个用C语言要如何定义呢？可否来一段注释详细的程序？网上找的只有略有提及，通俗一点说，就是我看不懂。
这个PWM的频率程序里面应该要如何计算？能达到25Khz么（不用这么精确，20-30Khz我都可以接受）？
这个PWM和中断，定时器，延时函数之间有没有什么关系呢？有这些函数会不会影响到PWM的频率？


一下是我在网上找到的一段程序，据说是用到内部硬件PWM的程序，大家帮忙看看，为小弟解解惑~
/**************************************************************
用STC12C5A60S2控制直流电机，PWM控制转速，按键s1、s2控制加速减速
因只控制一路电机所以只用到一路PWM，若用到两路则打开另一路即可
晶振为22.1184MHz，使用其他晶振时把延时函数改一下即可。
***************************************************************/

#include&lt;STC12C5A60S2.H&gt; //头文件

sbit s1 = P3^6;//加速控制&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sbit s2 = P3^7;//减速控制
sbit R1 = P0^3;
sbit R2 = P0^4;//R1和R2控制转向，一个高电平一个低电平

unsigned int z;

void delay_ms(unsigned int time)
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int x,y;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(x=time;x&gt;0;x--)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(y=229;y&gt;0;y--);
&#125;


void PWM_init (void)
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMOD=0x02; //设置PCA定时器
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CL=0x00; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CH=0x00;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAPM0=0x42; //PWM0设置PCA工作方式为PWM方式（0100 0010）
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP0L=0x00; //设置PWM0初始值与CCAP0H相同
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP0H=0x00; // PWM0初始时为0

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAPM1=0x42; //PWM1设置PCA工作方式为PWM方式（使用时删除//）
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP1L=0x00; //设置PWM1初始值与CCAP0H相同
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP1H=0x00; // PWM1初始时为0

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CR=1; //启动PCA定时器
&#125;
/**********************************************************************************************/

/*********************************************************************************************
函数名：PWM0占空比设置函数
调&nbsp;&nbsp;用：PWM0_set();
参&nbsp;&nbsp;数：0x00~0xFF（亦可用0~255）
返回值：无
结&nbsp;&nbsp;果：设置PWM模式占空比，为0时全部高电平，为1时全部低电平
备&nbsp;&nbsp;注：如果需要PWM1的设置函数，只要把CCAP0L和CCAP0H中的0改为1即可
/**********************************************************************************************/
void PWM0_set (unsigned char a)
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP0L= a; //设置值直接写入CCAP0L
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP0H= a; //设置值直接写入CCAP0H
&#125;
/*
void PWM1_set (unsigned char a)
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP1L= a; //设置值直接写入CCAP0L
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCAP1H= a; //设置值直接写入CCAP0H

&#125;*/
/**********************************************************************************************/


void main ()
&#123;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PWM_init(); //PWM初始化
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R1 = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R2 = 1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PWM0_set (1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z = 1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s1==0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delay_ms(500);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s1==0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PWM0_set (z);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(z &gt; 254)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; z=254;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s2==0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delay_ms(500);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s2==0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z--;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PWM0_set (z);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(z &lt; 1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; z=1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;
</textarea>
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] [解决办法]单片机输出PWM波，ds18b20采集温度因PWM的中断导致温度读取有错误的解决办法。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>