迅维网

查看: 16931|回复: 11
打印 上一主题 下一主题

[转帖][单片机教程3]用AVR M8模糊PID恒温控制改造936焊台

[复制链接]
跳转到指定楼层
1#
发表于 2009-8-14 14:02:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式 来自: 重庆 来自 重庆

马上注册,获取阅读精华内容及下载权限

您需要 登录 才可以下载或查看,没有帐号?注册

x
原文地址:
http://www.ourdev.cn/bbs/bbs_con ... 936&bbs_id=9999

作者:周远峰 153290557

搞了个焊台自己用放大用LM324比较差··不过温度还是可以稳定,用M8 AD10位 pwm10位温度范围为200-500
精确度1度··
因为程序的原因加上要慢慢整定所以每次升温到设定值前15度就开始整定··
有个缺点就是PID控制恒温时的那几度温度升的很慢··
设置部分还没写好
自己的思路是直接用那个可变电阻做设置
AD转换采样可变电阻来设定温度
设置一按键为温度设定
当按了那按键后可变电阻设定温度有效
没按的话不管你怎么转都不能调节温度
那部分写完后整个代码,发出来大家一起参考
发觉问题还很多的。。希望大家多提下意见,小弟初学的
还有如果要改的话可以不改那电路的引一条采样跟控制线出来直接连上M8也可以的

实物图片:


电路图





原代码(c 程序):
***************程序开始****************
project        :A/D转换数码管显示
chip type      : atmega8               
clock frequency:内部RC(INT) 8MHz
Author         :周远峰               
********************************/
#include "iom8v.h"
#include "macros.h"
#define osccal 0x7d                        
unsigned long adc_rel;              //处理后世界转换结果
unsigned long adc_rl;               //A/D转换结
unsigned int tmp;                   //设置的温度参数                          
unsigned char adc_mux;              //A/D通道
unsigned char led_buff[3]={0,0,0};  //显示缓存
signed int error0;                  //当前偏差
signed int error1;                  //上次偏差
signed int error2;                  //上上次偏差
signed char Kp;                     //比例常数
signed char Ki;                     //积分常数
signed char Kd;                     //微分常数
signed int kk1;                     //当前控制输出
signed int kk2;                     //上次控制输出
#define NB -3
#define NM -2
#define NS -1
#define ZO 0
#define PS 1
#define PM 2
#define PB 3
#pragma data:code     
//设置数据区位程序储存器
const unsigned char seg_table[16]={0x40,0x79,0x24,0x30,0x19,0x90,0x80,0x78,0x00,0x10,0x08,0x81,0x44,0x21,0x04,0x8c};
const unsigned char KP_table[49]={PB,PB,PM,PM,PS,ZO,ZO,PB,PB,PM,PS,PS,ZO,NS,PM,PM,PM,PS,ZO,NS,NS,PM,PM,PS,ZO,NS,NM,NM,PS,PS,ZO,NS,NS,NM,NM,PS,ZO,NS,NM,NM,NM,NB,ZO,ZO,NM,NM,NM,NB,NB};
const unsigned char KI_table[49]={NB,NB,NM,NM,NS,ZO,ZO,NB,NB,NM,NS,NS,ZO,ZO,NB,NM,NS,NS,ZO,PS,PS,NM,NM,NS,ZO,PS,PM,PM,NM,NS,ZO,PS,PS,PM,PB,ZO,ZO,PS,PS,PM,PB,PB,ZO,ZO,PS,PM,PM,PB,PB};
const unsigned char KD_table[49]={PS,NS,NB,NB,NB,NM,NS,PS,NS,NB,NM,NM,NS,ZO,ZO,NS,NM,NM,NS,NS,ZO,ZO,NS,NS,NS,NS,NS,ZO,ZO,ZO,ZO,ZO,ZO,ZO,ZO,PB,NS,PS,PS,PS,PS,PB,PB,PM,PM,PM,PS,PS,PB};
#pragma data:data   
//设置数据区回到数据储存器
/*********************************************************

延时函数

*********************************************************/
void delay_us(int time) //微秒级延时
{
do
time--;
while (time>1);
}
void delay_ms(unsigned int time)  //毫秒级延时
{
while (time!=0)
   {
   delay_us(1000);
   time--;
   }
}
/************************************************************
中断显示初始化
TIMER2 initialize - prescale:1024
WGM: Normal
desired value: 10mSec
actual value:  9.984mSec (0.2%)
*************************************************************/
void timer2_init(void)
{
TCCR2 = 0x00; //stop
ASSR  = 0x00; //set async mode
TCNT2 = 0xB2; //setup
OCR2  = 0x4E;
TCCR2 = 0x07; //start
DDRB=0xff;  //PC口为推挽1输出
PORTB=0xff; //PC口内部上拉
DDRD|=0xf1;
PORTD&=0x1f;  //关闭LED
}
/***********************************************

中断显示

*************************************************/
#pragma interrupt_handler timer2_ovf_isr:5
void timer2_ovf_isr(void)
{
unsigned char i;
static unsigned k;
SEI();
TCNT2 = 0xB2; //reload counter value
for(i=0;i<3;i++)
   {
   PORTB=led_buff;
   PORTD|=(1<<(i+5));//待显示的位置1
   delay_ms(1);
   PORTD&=0x1f;     //关闭LED
   }
}
/************************************************************

PWM初始化,OC1A口输出

*************************************************************/
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x00; //setup
OCR1A  = 200;
TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);//输出低电平
TCCR1B = (1<<CS11)|(1<<CS10); //
}
/*****************************************************

PID初始化

******************************************************/
void pidcalc_init(void)  
{
Kp=3;
Ki=3;
Kd=3;
kk1=0; //当前
kk2=100;
error0=0;
error1=0;
error2=0;
tmp=300;
}
void pidcalc_zizheng(void)
{
if (tmp>adc_rel)
   {
        if (kk2<500) kk2+=3;
        else kk2=500;
   }
if ((tmp-1)>adc_rel)
   {
        if (kk2<500) kk2+=3;
        else kk2=500;
   }
/*if ((tmp-2)>adc_rel)
   {
        if (kk2<600) kk2+=3;
        else kk2=600;
   }*/
if (tmp<adc_rel)
   {
   if (kk2>10) kk2-=3;
   else kk2=10;
   }
if ((tmp+1)<adc_rel)
   {
   if (kk2>10) kk2-=3;
   else kk2=10;
   }
/*if ((tmp+2)<adc_rel)
   {
   if (kk2>10) kk2-=3;
   else kk2=10;
   }
/*if (tmp>adc_rel)
   {
   if (Ki<200) Ki+=4;
   else Ki=400;
   }
if (tmp<adc_rel)
   {
   if (Ki>0) Ki-=4;
   else Ki=0;
   }  */
}
/*******************************************************

PID函数

********************************************************/
void pidcalc(void)
{
signed long KPP;
signed long KII;
signed long KDD;
signed int i;
signed char j;
error0=tmp-adc_rel;
j=error0-error1;
i=7*(3+error0)+(3+j);
if(i<49)
    {
     if (i>0)
            {
                Kp=KP_table;
                Ki=KI_table;
                Kd=KD_table;
                }
     }                        //输出                     
if ((tmp-15)<adc_rel)                         //比设定低一定值时开始PID
  {
   if((tmp+5)>adc_rel)                        //比设定高时关PID
       {
       KPP=Kp*(error0-error1);                //比例
       KII=error0*Ki;                         //积分
       KDD=Kd*(error0-(2*error1)+error2);     //微分
       kk1=(KPP+KII+KDD)*4+kk2;  
       if(kk1<0x3ef)
                   {
                           if (kk1>=10) OCR1A=kk1;   
                           else OCR1A=0;               
               }
           else
                   {   
                    OCR1A=0x3ff;
               }      
                           /*if((tmp-2)>adc_rel)
                                {
                                if(OCR1A<500) OCR1A+=20;
                                else OCR1A=500;
                                        }*/
           }
    else
           {
           //if (tmp<adc_rel)
                 // {
                  ///  if (OCR1A>50) OCR1A-=20;
                  //  else OCR1A=50;
           OCR1A=0;  
                 // }
       }
   }
else
   {
    OCR1A=0x3ff;
   }
error2=error1;
error1=error0;  
}
/***********************************************

ADC初始化

************************************************/
void adc_init(void)  
{
DDRC=0x00;
PORTC=0X00;
ADCSRA=0X00;
ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V为基准AREF外加滤波电容
ACSR=(1<<ACD);                  //关闭模拟比较器
ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//128分频
}
/*********************************************

ADC中断处理函数

**********************************************/
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
static unsigned i;
adc_rl+=ADC&0x3ff;
ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V位基准
ADCSRA|=(1<<ADSC); //启动AD转换   
if (i<2048)
    i++;
else  
     {
         adc_rel=adc_rl/2048;
         adc_rel=adc_rel*3/5;
         i=0;
         adc_rl=0;
         }
}
/******************************************************

ADC数据转压缩BCD

******************************************************/
void ADCtoBCD(unsigned int temp)
{
unsigned char i;
for (i=0;i<3;i++)
   {
   led_buff=seg_table[temp%10];/*temp%10求余数‘假设一个数是234那么234/10=23余4也就是查找4的段码*/
   
   temp=temp/10;// 234/10=23因为不处理小数实际就等于右移了
   }
   
}
/***************************************************************

主程序

***************************************************************/
void main(void)
{
unsigned char i;
unsigned int  k;
unsigned int adc_old;
unsigned long adc_ol;
unsigned int adc_o;
DDRD=0xff;
PORTD=0xf0;
OSCCAL=osccal;
TIMSK = 0x40; //timer interrupt sources
adc_mux=0;
adc_init();
timer1_init();
pidcalc_init();
SEI();
for(i=0;i<3;i++)
   led_buff=seg_table[8];
for(i=0;i<200;i++)
   timer2_init();
   adc_old=0;
   adc_rel=0;
  while(1)
     {
                if(adc_old!=adc_rel)//ADC更新完毕就执行数据处理
                 {
                      adc_old=adc_rel;
                          pidcalc();
                          pidcalc_zizheng();
                            if(k<5)
                                    {
                                        k++;
                                        adc_ol+=adc_old;
                                        }
                                else
                                    {
                                        adc_o=adc_ol/5;
                                        adc_ol=0;
                                        k=0;
                                        }        
                          }  
            ADCtoBCD(adc_o);  
         }
}
***************程序结束****************

2#
发表于 2009-8-14 22:11:37 | 只看该作者 来自: 重庆 来自 重庆
AVR M8中文手册: ATmega8_cn.pdf (2.45 MB, 下载次数: 131)

回复 支持 反对

使用道具 举报

3#
发表于 2009-8-14 22:42:41 | 只看该作者 来自: 重庆 来自 重庆
ATmega8-16PU 现在价格6元左右,上面提供了可完成这个项目的所有编译、下载程序和工具。很适合大家学习、实践单片机的应用。

回复 支持 反对

使用道具 举报

4#
发表于 2009-8-15 07:09:14 | 只看该作者 来自: 河南平顶山 来自 河南平顶山
这个东西对我还是有用的,最近刚接触单片机89s52,这个保存下,现在看不懂,以后应该没问题,或者哪个大虾,帮我解释一下,谢啦

回复 支持 反对

使用道具 举报

5#
发表于 2009-8-15 21:11:31 | 只看该作者 来自: 重庆城口县 来自 重庆城口县
简单的讲下过程:
1、先用CVAVR将C代码编译成M8的执行代码。
2、用简易并口下载线连接M8 ISP接口和PC的并口。
3、运行 双龙下载程序 将代码写入M8。
4、调试M8的目标板。

如有需要修改代码的地方,重复上面的过程。

回复 支持 反对

使用道具 举报

6#
发表于 2010-2-8 23:55:17 | 只看该作者 来自: 河北保定 来自 河北保定
恩这个我做过的...效果还行 ,恒温对大元件有些吃力..不过一般的焊接足够了..

回复 支持 反对

使用道具 举报

7#
发表于 2010-3-9 22:20:37 | 只看该作者 来自: 四川资阳 来自 四川资阳
现在的M8 不好买了,8M的都要8元。(还是二手解熔丝的) 16MHZ的,得10元以上!!

回复 支持 反对

使用道具 举报

8#
发表于 2010-3-9 22:22:36 | 只看该作者 来自: 四川资阳 来自 四川资阳
我才买了10片8M的 M8 准备做那个东西,不过。这个AVR的编程比51要麻烦些。一但烧错了熔丝,又没有高压编程器的话,就不好搞了,收到了我用洞洞板做一个LZ的那个东东!

回复 支持 反对

使用道具 举报

9#
发表于 2010-4-2 03:13:33 | 只看该作者 来自: 广西南宁 来自 广西南宁
不知老大的焊台搞好了没有?
最近也想DIY一个。

整体的思路是这样:
稳压电源经电阻、测温电阻分压后送到ADC,
ADC结果与预设温度数据比较,得到一个差值,
根据这个差值由CPU控制可控硅导通角。

AC过零检测电路在AC电压过零时给CPU发送一次中断。(高优先级)
中断服务程序完成以下工作:1。做一次ADC,其结果计算后送LED显示当前温度;2。比较当前温度与预设温度,根据其差值设定计数器初值(差值大则计数器初值小),然后启动计数器。3。计数完成后使可控硅导通。4。退出中断服务程序。

控制:设三个按键“+”,“-”,“显示/设定”。“显示/设定”按键用来切换LED显示“当前温度”和修改“预设温度”两种状态。“+”“-”键只在显示修改“预设温度”时有效,修改后再按“显示/设定”保存并转化显示状态。
在显示状态按下“显示/设定”键后触发低优先级中断。由中断服务程序完成修改“预设温度”功能。

显示:设3位LED数码管和2个LED灯。一个灯用来指示数码管状态(显示/设定温度),一个灯用来指示加热/恒温。

校准:现在还没想好。

芯片还没定,因为熟悉的C51没有ADC。过零检测电路打算用全波整流加三极管。
想要的东西不是产品,而是DIY的过程。

回复 支持 反对

使用道具 举报

10#
发表于 2010-4-21 20:18:58 | 只看该作者 来自: 广东东莞 来自 广东东莞

我今天刚买的,现在的ATmega8价格已经升到10元了。

回复 支持 反对

使用道具 举报

11#
发表于 2014-3-7 01:53:44 | 只看该作者 来自: 广东广州 来自 广东广州
路过。。。。。。

回复 支持 反对

使用道具 举报

12#
发表于 2014-6-8 19:43:15 | 只看该作者 来自: 江苏南京 来自 江苏南京
很使用的东西,顶。

回复 支持 反对

使用道具 举报

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

本版积分规则

快速回复 返回顶部 返回列表
附近
店铺
微信扫码查看附近店铺
维修
报价
扫码查看手机版报价
信号元
件查询
点位图 AI维修
助手



芯片搜索

快速回复