株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。新規開発案件のご依頼をお待ちしております。

*

Tiva C EK-TM4C123GXL(その11) ADコンバータ

   

Tiva C EK-TM4C123GXLを使ってみるの11回目です。前回は、UART通信でのデバッグでしたが、今回は、ADコンバータを使ってみます。

以下のメーカのサイトを見ながらプログラムを作っていきます。
Getting Started with the TIVA™ C Series TM4C123G LaunchPad

更に、このサイトで下の方の、Workshop MaterialのThe workbookを見ながら作ります。
直接のPDFファイルへのリンクは、The workbook PDF です。

このPDFファイルのLab5のプログラムそのままです。詳細は、このPDFファイルのLab5のあたりを参照して下さい。ソースは以下からダウンロード出来ます。
lab5そのままのプロジェクト一式
出力用UARTを追加したプロジェクト一式

まずは、簡単にですが一般的なADコンバータについてです。

AD コンバータとは、アナログ信号をデジタル信号に変換する電子回路(機能)のことです。計測機器、音声、映像機器、医療機器等、アナログデータをデジタルで扱うには、必須となっていると思います。

このADコンバータで、重要な要素が、分解能とサンプリング速度です。分解能とは、ビットで表現され、アナログ(入力電圧)を何分割出来るかのことです。例えば、10ビットなら1024分割となります。サンプリング速度とは、単位はサンプル/秒(SPS)で1秒間に何回変換が可能かを表現します。例えば、1SPS は1秒間に1回、1MSPS (Mはミリオン)は1秒回に100万回ということになります。

次に今回のTiva CのADコンバータについてです。Tiva C(MCU TM4C123GH6PM)では、ADC0とADC1の2つのモジュールがあります。
分解能はいずれも12ビットで、サンプリング速度は、いずれも1MSPS (Mはミリオン)で上の例と同じで、1秒回に最大100万回の変換が可能という性能です。より詳細は、上のPDFファイルのLab5を参照して下さい。

それでは、サンプルプログラムそのままですが、以下のソースを試してみました。処理は、内蔵の温度センサの値をADCで取得して摂氏の温度と華氏の温度を計算しています。コメントは、私が書きました。参考程度に見て下さい。

一応、毎回書こうと思いますが、TivaWare付属のサンプルプログラム等を見ていると、ROM_ で始まっている関数をよく見かけますが、ROM_ の方は、ROM内蔵版です。こちらを使うとプログラム全体の大きさが小さくなりますが、ここでは特にサイズを気にする程でもないので、普通にリンクして使う、ROM_ が付いていない通常版の関数を使います。

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"

int main(void)
{
    uint32_t ui32ADC0Value[4];          //アナログデータの値
    volatile uint32_t ui32TempAvg;     //4つの値の平均を計算       
    volatile uint32_t ui32TempValueC;  //温度(摂氏)
    volatile uint32_t ui32TempValueF;  //温度(華氏)

    //クロックを40MHzに設定
    SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    //ADC0にクロックを供給
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //ADC0の構成の定義(シーケンスNoを1、プロセッサをトリガ、最優先順位)
    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
    
    //内蔵温度計からのADCシーケンスを4ステップ定義
    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_TS);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_TS);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_TS);
    ADCSequenceStepConfigure(ADC0_BASE,1,3,ADC_CTL_TS|ADC_CTL_IE|ADC_CTL_END);  //シーケンス最後の設定も追加
    
    //ADC0のシーケンス有効
    ADCSequenceEnable(ADC0_BASE, 1);

    while(1)
    {
        //このADCシーケンスの割り込みフラグをクリア
        ADCIntClear(ADC0_BASE, 1);
        
        //ここからトリガにしてこのADCシーケンスを開始
        ADCProcessorTrigger(ADC0_BASE, 1);

        //完了待ち
        while(!ADCIntStatus(ADC0_BASE, 1, false))
        {
        }
        
        //データを取得して、4つの値の平均を計算
        ADCSequenceDataGet(ADC0_BASE, 1, ui32ADC0Value);
        ui32TempAvg = (ui32ADC0Value[0] + ui32ADC0Value[1] + ui32ADC0Value[2] + ui32ADC0Value[3] + 2)/4;
        
        //温度値に変換
        ui32TempValueC = (1475 - ((2475 * ui32TempAvg)) / 4096)/10;
        ui32TempValueF = ((ui32TempValueC * 9) + 160) / 5;
    }
}

処理としては、ADC0を使って内蔵の温度センサから温度を計算しています。割り込みは使わないで、while()ループで毎回取得しています。ADCの使い方としては、1番というシーケンスを定義して、そのシーケンスで温度センサから4回取得するように設定しています。その4回の平均を計算しています。温度への変換ですが、データシートには詳細が書いてあるだろうということで、特に触れません。ご了承下さい。ただ、計算結果は整数でここでは浮動小数点は使っていないということだけ認識しておきます。

このまま実行すると、計算結果の出力がないので、とりあえずデバッガでブレークして確認します。デバッガでも分かるのですが、ここで前回のUARTデバッグを使ってみます。以下のようなソースになります。

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"

//必要なファイルを追加
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/pin_map.h"

#include "uartstdio.h"

//*****************************************************************************
//
// Configure the UART and its pins.  This must be called before UARTprintf().
// (※サンプルのhello.cのConfigureUART()関数をそのまま利用しています。)
//
//*****************************************************************************
void
ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}

//*****************************************************************************
//
// ADCのメイン関数
//
//*****************************************************************************
int main(void)
{
    uint32_t ui32ADC0Value[4];          //アナログデータの値
    volatile uint32_t ui32TempAvg;     //4つの値の平均を計算       
    volatile uint32_t ui32TempValueC;  //温度(摂氏)
    volatile uint32_t ui32TempValueF;  //温度(華氏)

    //クロックを40MHzに設定
    SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    //ADC0にクロックを供給
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //ADC0の構成の定義(シーケンスNoを1、プロセッサをトリガ、最優先順位)
    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
    
    //内蔵温度計からのADCシーケンスを4ステップ定義
    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_TS);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_TS);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_TS);
    ADCSequenceStepConfigure(ADC0_BASE,1,3,ADC_CTL_TS|ADC_CTL_IE|ADC_CTL_END);  //シーケンス最後の設定も追加
    
    //ADC0のシーケンス有効
    ADCSequenceEnable(ADC0_BASE, 1);
    
    //UARTの初期化
    ConfigureUART();

    while(1)
    {
        //このADCシーケンスの割り込みフラグをクリア
        ADCIntClear(ADC0_BASE, 1);
        
        //ここからトリガにしてこのADCシーケンスを開始
        ADCProcessorTrigger(ADC0_BASE, 1);

        //完了待ち
        while(!ADCIntStatus(ADC0_BASE, 1, false))
        {
        }
        
        //データを取得して、4つの値の平均を計算
        ADCSequenceDataGet(ADC0_BASE, 1, ui32ADC0Value);
        ui32TempAvg = (ui32ADC0Value[0] + ui32ADC0Value[1] + ui32ADC0Value[2] + ui32ADC0Value[3] + 2)/4;
        
        //温度値に変換
        ui32TempValueC = (1475 - ((2475 * ui32TempAvg)) / 4096)/10;
        ui32TempValueF = ((ui32TempValueC * 9) + 160) / 5;
        
        //UART出力
        UARTprintf("TempValueC = %d\n", ui32TempValueC);
    }
}

UART出力には、日本で馴染みのある摂氏だけ出力しています。これを実行してTeraTermを接続した画面が以下です。それらしい結果が確認出来ました。今回はここまでです。
uarttmp

 - Tiva C, 使ってみた

AdSense

AdSense

  関連記事

no image
Tiva C EK-TM4C123GXL(その4)workbookを使う

Tiva C EK-TM4C123GXLを使ってみるの4回目です。 前回までで、 …

no image
Microsoft AzureでASP.NETサイトを公開してみる(その2)ASP.NETサイトの作成

Microsoft AzureでASP.NETサイトを公開してみるの2回目です。 …

3Dプリンターを使ってみた(その2)AutoDesk 123D Creature導入

3Dプリンターを使ってみたの2回目です。前回は私が3Dプリンターに関して今までや …

no image
Tiva C EK-TM4C123GXL(その3)EWARMでビルド確認

Tiva C EK-TM4C123GXLを使ってみるの3回目です。 今回はEWA …

no image
Tiva C EK-TM4C123GXL(その2)開発環境

Tiva C EK-TM4C123GXLを使ってみるの2回目です。 前回は起動確 …

no image
Microsoft AzureでSQL DBを使ってみる(その2)Azureでの公開

前回の続きです。Microsoft Azure(以下、Azureと表記します。) …

no image
Microsoft AzureでASP.NETサイトを公開してみる(その1)概要と開発環境

Microsoft Azureのサイト上で、ローカル環境で開発したASP.NET …

Tiva C EK-TM4C123GXL(その1)起動確認まで

Tiva C EK-TM4C123GXLというマイコン評価ボードを使ってみました …

Raspberry PiでAC100V(ソリッド・ステート・リレー)制御

Raspberry PiでAC100VのON/OFF制御を試してみました。今回そ …

no image
Tiva C EK-TM4C123GXL(その7) ボード上のスイッチを使う

Tiva C EK-TM4C123GXLを使ってみるの7回目です。 前回の続きで …