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

システム開発エンジニアの西田五郎が運営しております。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, 使ってみた

執筆者:

関連記事

AndroidでUSBシリアル通信(その4)ライブラリサンプルの内容

AndroidでUSBシリアル通信の4回目です。今回は、前回動作確認をしたライブラリサンプルの内容、つまり設定ファイルやプログラムの構成、プログラムの仕様等を見ます。 ライブライは以下です。より詳細は …

no image

Microsoft AzureでASP.NETサイトを公開してみる(その3)Visual Studio EEからの公開

Microsoft AzureでASP.NETサイトを公開してみるの3回目です。今回は、前回Visual Studio Express 2013 for Web で作成したプロジェクトをそのままをVi …

no image

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

Microsoft Azureのサイト上で、ローカル環境で開発したASP.NETのサイトを公開するまでの手順についてです。(※簡単にサイト公開までということで、データベースは利用しません。ご了承下さい …

no image

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

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

no image

Tiva C EK-TM4C123GXL(その9) UART通信

Tiva C EK-TM4C123GXLを使ってみるの9回目です。前回は、タイマと割り込みでしたが、今回は、UART通信です。 以下のメーカのサイトを見ながらプログラムを作っていきます。 Gettin …