温度制御2 (温度制御1の装置の性能)


温度制御1 (PWM、オンオフ動作)の装置の性能を 下の表に示します。

使用したソフトを下に記載しておきます。


PWMオンオフ出力を20分間出力した後の
湯沸しポットの温度
PWMオン時間 [%]初期の湯沸しポットの温度 [℃]20分後の湯沸しポットの温度 [℃]
521.323.3
1023.330.2
1530.238.7
2038.749.5
2549.561.7
3061.774.2
3574.275.5


How to Compile (コンパイルのしかた)

プログラム
/*
 * temp_ctrl2.c
 *
 * Created: 2017/03/14 22:27:59
 * Author : User
 */ 

/*
 *  short pwm_on_time;      // PWMオン時間 (0 〜 100%)
 *  上記の変数 pwm_on_time を 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 0
 *  と変化させ、そのオン時間 (%) に対するポットの温度を RS-232C(115200 8-N-1)で出力する
 *
 *  ATmega328P
 *
 *
 *  Fuses(システムクロック:20MHz)
 *
 *
 *              ディホルト  Int. RC Osc.    水晶        外部クロック
 *              DISABLED    2.7V            2.7V        2.7V
 *              8/8MHz      8MHz
 *  EXTENDED    0xFF        0xFD            0xFD        0xFD
 *  HIGH        0xD9        0xD9            0xD9        0xD9
 *  LOW         0x62        0xE2            0xF7        0xE0
 */

#include <stdio.h>          /* sprintf() */
#include <string.h>         /* strlen() */
#include <avr/io.h>
#include <avr/interrupt.h>
///#define F_CPU 20.0E6     /* 20 MHz */
///#include <util/delay.h>

#define USEC 1024
#define round(x)     ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

typedef struct t_systim
{
    short utime;            /* 上位16bit */
    unsigned long ltime;    /* 下位32bit */
} SYSTIM;

///void delay_us(unsigned short t){while(t--) _delay_us(1);}
///void delay_ms(unsigned short t){while(t--) _delay_ms(1);}
void initADC(void);
void initTIMER(void);
void get_tim(SYSTIM *p_tim);
void initUSART0(void);
void Send0(char *str);

short ad_data;
SYSTIM SYSCK;

int main(void)
{
    SYSTIM tim;
    static unsigned long ot[3];
    float ondo;             /* 温度 (0.0 〜 110.0℃) */
    short pwm_on_time;      /* PWMオン時間 (0 〜 100%) */
    char buff[32], buff2[8];
    int len;

    /* ATmega328P */
    DDRB = 0b00000101;      /* XTAL2 XTAL1 SCK   MISO  MOSI  OC1B  ----- LED   */
    DDRC = 0b00000000;      /* xxxxx RESET ----- ----- ----- ----- ----- ----- */
    DDRD = 0b00000000;      /* ----- ----- ----- ----- ----- ----- TXD   RXD   */
    PORTB = 0b00111010;
    PORTC = 0b00111110;
    PORTD = 0b11111100;

    initADC();
    initTIMER();
    initUSART0();

    /*
     *  WGM13 WGM12 WGM11 WGM10 動作種別     TOP値
     *    1     1     1     1   高速PWM動作 OCR1A
     *
     *  COM1A1 COM1A0 COM1B0 COM1B0
     *  0      0      1      0      比較一致でLow、BOTTOMでHighをOC1Bピンへ出力(非反転動作)
     */
    TCCR1A = 0b00100011;    /* 一致時(OCR1B)Low, TOP->BOTTOM(OCR1A)でHighを */
                            /* OC1Bピンへ出力(非反転動作), 高速PWM動作 */
/// TCCR1B = 0b00011001;    /* (1 / 20MHz) * 65535 = 3.3mS */
/// TCCR1B = 0b00011010;    /* (8 / 20MHz) * 65535 = 26mS */
    TCCR1B = 0b00011011;    /* (64 / 20MHz) * 65535 = 210mS */
/// TCCR1B = 0b00011100;    /* (256 / 20MHz) * 65535 = 839mS */
/// TCCR1B = 0b00011101;    /* (1024 / 20MHz) * 65535 = 3355mS */
    OCR1A = 0xffff;         /* TOP->BOTTOMでHigh, 固定 */
    OCR1B = 0;              /* 一致時Low、可変(0はPWM出力on時間0%) */
    sei();

    Send0("START\r");

    get_tim(&tim);
    ot[0] = tim.ltime;
    ot[1] = tim.ltime;
    ot[2] = tim.ltime;
    /* pwm_on_timeの初期値 */
    pwm_on_time = 5;
    OCR1B = round(65535.0 * pwm_on_time / 100.0);
    while(1){
        get_tim(&tim);
        if((unsigned long)(tim.ltime - ot[0]) >= 500000/USEC){  /* 500mS */
            ot[0] = tim.ltime;
            PORTB ^= 0b00000001;
        }

        get_tim(&tim);
        if((unsigned long)(tim.ltime - ot[1]) >= 1000000/USEC){ /* 1S */
            ot[1] = tim.ltime;

            /* 温度を得る 例 12.3℃ */
            ondo = 1100.0 * ad_data / 10230;    /* 0.0〜110.0℃ */

            get_tim(&tim);
            if((unsigned long)(tim.ltime - ot[2]) >= 1200000000/USEC){ /* 20Min */
                ot[2] = tim.ltime;
                /* pwm_on_time --> 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 */
                if(5 <= pwm_on_time && pwm_on_time < 50)
                    pwm_on_time += 5;
                else
                    pwm_on_time = 0;
                OCR1B = round(65535.0 * pwm_on_time / 100.0);
            }
            
            /* 表示例 pwm_on_time = 10%, 14.2℃  */
            sprintf(buff2, "%ld", round(ondo * 10));
            len = strlen(buff2);
            buff2[len + 1] = buff2[len];
            buff2[len] = buff2[len - 1];
            buff2[len - 1] = '.';
            sprintf(buff, "pwm_on_time = %d%%, %s℃\r", pwm_on_time, buff2);
            Send0(buff);
        }
    }
}

void initADC(void)
{
    ADCSRA = 0b10101111;    /* AD変換イネーブル, AD自動変換イネーブル,AD変換割り込みイネーブル */
                            /* 1/128クロック(最大変換時間=200uS @16MHz, 156uS @20MHz) */
    ADCSRB = 0b00000011;    /* タイマ/カウンタ0比較一致A */
    ADMUX = 0b11000000;     /* 基準電圧 = 1.1V(@atmega328p), 右詰, アナログ入力 = ADC0 */
}

ISR(ADC_vect)
{
    static long result;
    static short counter;

    result += ADC;
    counter++;
    if(counter >= 100){
        counter = 0;
        ad_data = (short)(result / 100);
        result = 0;
    }
}

void initTIMER(void)
{
    TCCR0A = 0b00000010;    /* CTC動作 */
    TCCR0B = 0b00000100;    /* clk / 256 */
    OCR0A = 80 - 1;         /* (256 / 20MHz) * 80 = 1024uS */
    TIMSK0 = 0b00000010;    /* 比較A割り込み要求有効 */
}

ISR(TIMER0_COMPA_vect)
{
    if(++SYSCK.ltime == 0)
        ++SYSCK.utime;
}

void get_tim(SYSTIM *p_tim)
{
    cli();
    *p_tim = SYSCK;
    sei();
}

void initUSART0(void)
{
    UBRR0 = 21;             /* U2X0 = 1, 115200ボー/20MHzクロック */
    UCSR0A = 0b00000010;    /* U2X0 = 1 */
    UCSR0B = 0b00001000;    /* 送信イネーブル */
    UCSR0C = 0b00000110;    /* 8ビット, パリティなし, ストップ・ビット1 */
}

/*
 *  1データ送信
 */
void Tx0(char data)
{
    while((UCSR0A & _BV(5)) == 0)
        ;
    UDR0 = (unsigned char)data;
}

/*
 *  文字列を送信
 */
void Send0(char *str)
{
    while(*str != '\0'){
        Tx0(*str);
        str++;
    }
}


真空管
戻る