PIC16F18346の基本動作から応用プログラムまでを学びます。

ホーム
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
    
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
音声温度計
2020-06-23

温度に比例した電圧を出力する温度センサー(MCP9700)を使って、測定した温度をLCDに表示、さらに、PushSWを押すと温度を音声で知らせるプログラムです。省電力にするために温度の更新は4秒に一度としほとんどの時間は、SLEEPモードになっています。

EEPROMには、言葉を細分化しその要素ごとに無音を0.1秒間挟んで記録してあります。各要素の開始アドレスと終了アドレスは、配列に記録してあるため、測定した温度の値は、この配列を参照しながらPWMで再生し温度を音声で知らせています。

プログラム

main.c プログラムを示します。
必要となるほかのプログラムは、まとめて圧縮してあります。

音声温度計ソースファイル b07TempVoice.zip

main.c

/*************************************
 *  File name: EEPROM 温度を音声再生
 *  EEPROM に記録された 8kHz 8bit PCMデータを再生
 * System ClockはConfigで内部32MHzに設定
 *  LEDも連動した点灯
 *        PWM(LED)    RC5
 *        PushSW      RC4
 *        温度入力      RC2
 *
 * Language: MPLABX XC8 v2.10
 * PIC16F18346 on 20pin demoboard
 * Created on 2020-6-16
 **************************************/

#include <xc.h>
#include <stdio.h>
#include "I2C_EEPROM.h"
#include "words123.h"
#include "i2cLCD.h"
#include "config_sys.h"

//#define _XTAL_FREQ 32000000      // delay_ms(x) のための定義

void fadeIn(void);
void fadeOut(void);
void speekSin(int);
void speekWords(char*);
void speekTemp(int);
void speekTen(char,char);
void speekOne(char,char);
void speekDot(char);
void speekBlw(char);

// ******************* main *************************************
void main() {
  int temp = 0;
  i2c_MasterInit(400000);   // i2c 関連初期化 400KHz クロック
  LCD_int();                // LCDを初期化
  sys_int();                // PWM SW ADC Timerを初期化
  printf("Temp");
  TMR1IE = 1;               // Timer1割込み許可
  PEIE = 1;                 // ペリフェラル割込み許可
  INTE = 1;                 // Pin割込み許可

  // -------------------------------------------
  while(1){
    // ----- SLEEP状態にする ------------------
    SLEEP();
    NOP();
    // ----- ウェイクアップ --------------------
    TMR1IF=0;       // Timer1割込みフラッグクリア
    temp = 0;
    for(char i=0;i<32;i++){     // 32回測定し平均する
        __delay_ms(5);          // ADチャージ時間
        GO = 1;                 // AD変換開始
        while(GO);              // AD変換終了待ち
        temp += (ADRES - 500);
    }
    temp /= 32;
    LCD_posyx(1,0);             // 下段にカーソル移動
    printf("%3d.%d C",temp/10,temp%10);  // 結果表示
    // SWが押されたなら ------------------------
    if(INTF){
      speekTemp(temp);    // 温度を発声
      while(!PushSW);     // SWが離れるのを待つ
      __delay_ms(10);     // チャタリング防止
      INTF = 0;           // Pin割込みフラグクリア
    }
  }
  // -------------------------------------------
} //main

// PWM出力を0vから無音状態(0x80)にゆっくり上げる
void fadeIn(void){
  TRISC5 = 1;                     // PWM5 RC5 Output OFF
  PWM5EN = 1;                     // PWM ON
  PWM5DCH = 0;                    // 出力0vにを設定
  TMR2IF = 0;                     // フラッグをクリア
  while(! TMR2IF);                // Timerカウントアップ待つ
  TMR2IF = 0;                     // フラッグをクリア
  TRISC5 = 0;                     // PWM5 RC5 Output ON
  for(char i=0; i<0x80; i++){     // 無音状態(0x80)にゆっくり設定
    while(! TMR2IF);              // Timerカウントアップ待つ
    TMR2IF = 0;                   // フラッグをクリア
    PWM5DCH = i;                  // デュティサイクルを設定
  }
}
// PWM出力を無音状態(0x80)から0vにゆっくり下げる
void fadeOut(void){
  for(char i=0x80; i>0; i--){     // ovにゆっくり設定
    while(! TMR2IF);              // Timerカウントアップ待つ
    TMR2IF = 0;                   // フラッグをクリア
    PWM5DCH = i;                  // デュティサイクルを設定
  }
  PWM5EN = 0;                     // PWM OFF
}

// 音声で読み上げ ------------------------------------
void speekWords(char*step){
  char wd,sp,data,mBlock;
  unsigned long addr = 0;   // EEPROM memory address
  while(*step < 50){
    wd=*step++;  sp=*step++;
    addr = StartAdd[wd];                  // PCM 開始アドレス
    mBlock = EEPROM_AddressSet(addr);     // 内部アドレス設定
    while(addr++ < EndAdd[wd]){           // データ終了まで
      while(! TMR2IF);                    // Timerカウントアップ待つ
      TMR2IF = 0;                         // フラッグをクリア
      data = EEPROM_ReadCurrent(mBlock);  // デュティサイクルを設定
      PWM5DCH = data;                     // デュティサイクルを設定
      if (addr == 0x10000)                    // ブロック境界なら
          mBlock = EEPROM_AddressSet(addr);   // 内部アドレス書換え
    }   //while
    delay_ms(sp);
  }
}

void speekTemp(int temp){
  fadeIn();
  speekSin(temp);                   // 符号を読み上げ
  temp = abs(temp);                 // 絶対値をとる
  char tempTen =  temp / 100;       // 10の位を抽出
  char tempOne = (temp / 10) % 10;  // 1の位を抽出
  char tempBlw =  temp % 10;        // 小数点以下を抽出
  speekTen(tempTen,tempOne);        // 10の位を読み上げ
  speekOne(tempTen,tempOne);        // 1の位を読み上げ
  speekDot(tempBlw);                // 小数点を読み上げ
  speekBlw(tempBlw);                // 小数点以下を読み上げ
  fadeOut();
}
// 符号を読み上げ ----------------------------------------
void speekSin(int temp){
  if(temp < 0){
    char words[] = {24,80,99};
    speekWords(words);
  }
}
// 10の位を読み上げ ----------------------------------------
void speekTen(char tempTen,char tempOne){
  // 10の位が 0 なら、すぐにReturn
  if(tempTen == 0) return;
  if(tempOne == 0){
    // 1の位が 0 なら、
    char words[] = {20,0,21,110,99};
    if(tempTen == 1){ words[1] = 110; words[2] = 99;}
    else if(tempTen == 2) words[0] = 5;
    else if(tempTen == 3) words[0] = 6;
    else if(tempTen == 4) words[0] = 8;
    else if(tempTen == 5) words[0] = 11;
    speekWords(words);
  }else{
    // 1の位が 0 以外なら、
    char words[] = {tempTen * 2,20,23,20,99};
    if(tempTen == 1){ words[0] = 22; words[2] = 99;}
    else if(tempTen == 3)  words[3] = 70;
    else if(tempTen == 5)  words[0] = 11;
    speekWords(words);
  }
}
// 1の位を読み上げ ----------------------------------------
void speekOne(char tempTen,char tempOne){
  if((tempTen != 0)&(tempOne == 0)) return;
  char words[] = {tempOne * 2,50,99};
  if(tempOne == 6)      words[1] = 150;
  else if(tempOne == 8) words[1] = 100;
  else if(tempOne == 1) words[1] = 120;
  speekWords(words);
}
// 小数点を読み上げ ----------------------------------------
void speekDot(char tempBlw){
  char words[] = {25,0,99};
  if(tempBlw == 3)      words[1] = 80;
  else if(tempBlw == 9) words[1] = 80;
  speekWords(words);
}
// 小数点以下を読み上げ ----------------------------------------
void speekBlw(char tempBlw){
  char words[] = {tempBlw * 2 + 1,0,26,0,99};
  speekWords(words);
}