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

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

Tiva C 使ってみた

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

AdSense

AdSense

-Tiva C, 使ってみた

執筆者:

関連記事

no image

Tiva C EK-TM4C123GXL(その8) タイマと割り込み

Tiva C EK-TM4C123GXLを使ってみるの8回目です。前回は、ボード上のスイッチを使いましたが、今回はタイマと割り込みです。 以下のメーカのサイトを見ながらプログラムを作っていきます。 G …

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

3Dプリンターを使ってみたの2回目です。前回は私が3Dプリンターに関して今までやってきたことを書きました。今回は3Dプリンターでモデルを作る際に使った Autodesk 123D Creature(こ …

no image

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

Tiva C EK-TM4C123GXLを使ってみるの2回目です。 前回は起動確認まででした。今回は開発環境についてです。 以下の開発環境を使っています。 統合開発環境 ARM用 IAR Embedd …

3Dプリンターを使ってみた(その3)Autodesk 123D Creatureで骨格作り

3Dプリンターを使ってみたの3回目です。前回は、Autodesk 123D Creature(ここからは、123D Creatureと書きます。)でモデルを作る際の大きな流れを書きました。今回は骨格と …

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

Raspberry PiでAC100VのON/OFF制御を試してみました。今回そのために以下のソリッド・ステート・リレーキットを利用しました。この製品を選んだ理由としては「扱いが簡単」かなと思ったから …