LPC1343 7seg LEDを制御する 準備編

出来た事

1.7seg LEDの制御
2.タイマー(SysTickTimer)
3.GPIO制御

開発Listへ戻る

7seg LEDを使ってGPIOの使い方を学びたいと思います。


準備物

Vf=1.8V でIf=20mAです。
LPC1343の3.3V電源を使う場合は

R=(Vdd-Vf)/If=(3.3-1.8)/0.02 = 75Ωを使用すれば
Typ状態で点灯できます。

しかし、20mAも引っ張りたくない事と、手持ちの抵抗でちょうど良いものと
いうことで160Ωを使うことにしました。
電流は10mA以下になります。

LPC1343への接続図

  • GPIO2の0-6bitに接続
  • 7segのdotは今回使いません。(1digitなので小数点は不要です)

私の実装例です。



7seg LED A-551はアノードコモンです。
したがって、LEDを点灯させるためにはGPIOをGNDにする必要があります。

7segLEDの点灯デコード
1を表示する場合を例にします。

あくまで今回の私の接続の場合ですが
"1"を表示するにはP2.6, P2.4を点灯する(=GNDにする)必要があります。

1→ GPIO[6:0]=010 1111 (2進数)です。
ヘキサ表記だと 0x2Fです。

このルールでデコードを作ると以下になります。
0→0x02
1→0x2F
2→0x41
3→0x05
4→0x2C
5→0x14
6→0x10
7→0x27
8→0x00
9→0x04

次回は動作&コードです。

LPC1343 UARTでADCを制御する 2/2

UARTでADCを制御する!のコードです。

回路構成は前の記事参照

その他、開発記事List参照

今回は少しコード量が多かったので複数ファイル構成にしました。
C言語もよくわかってない自分ですが何とかできました!!
インターネット上で親切に説明していただいているサイトが多くあったので
難しくはなかったです。

コード構成は以下です。
C projectを作成してファイルを追加してコピペで動作するはずです。

main.c : ハイパーターミナルで"ad0"と入力するとADC実行&値を返す
adc0.c : AD0のイニシャライズとAD変換実行
adc0.h
uart.c : UART部分(エレキジャックさんの記事参照)
uart.h


main.c
ベースのコードがあるエントリ:「UART Rx回路を入れてみる」
変更点

  • UARTとADCを別ファイル化
  • ADC制御はadc0_initとadc0readという関数に分けて使用
  • ADC結果をUARTで送信するときにcharに変換しなければならないのでitoa関数を使用
  • itoa関数を使うためにをinclude

#ifdef __USE_CMSIS
#include "LPC13xx.h"
#endif

#include
#include
#include "adc0.h"
#include "uart.h"

__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

#include
#include    //int-> char変換 itoi
// Main loop
int main(void) {
// Variable declaration
char line[40]; // Line buffer;
char *s; // return value
char p[4]; // AD0 value
int ad0data;

// Initialize UART
uart_init(9600);
uart_puts("HELLO WORLD\r\n");
adc0_init();

// Enter an infinite loop, just echo lines
while (1) {
// Get a line from UART
s = uart_gets(line, sizeof line);
if (s) {
// Put a line into UART if valid
if(!strcmp(s,"ad0")){
ad0data=adc0read();
itoa(ad0data, p, 10);
uart_puts(p);
uart_puts("\r\n");
}
else{
uart_puts("na");
uart_puts("\r\n");
}
}
}
}


adc.c
ベースのコードがあるエントリ:「ADCを使ってみる。」
変更点

  • adc0_init,adc0readの二つの関数に分割

#include "LPC13xx.h" /* LPC13xx Peripheral Registers */
#include "adc0.h"


void adc0_init(void) {
LPC_SYSCON->PDRUNCFG &= ~(0x1<<4); // See data sheet
LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<13); // See data sheet
LPC_IOCON->JTAG_TDI_PIO0_11 &= ~0x9F; // PIO0_11=Analog input
LPC_IOCON->JTAG_TDI_PIO0_11 |= 0x02; // PIO0_11=ADC0

LPC_ADC->CR |=0x00000001; // ADC0=on
//Clkdiv This time clk=4MHz (max=4.5MHz)
LPC_ADC->CR = ((SystemCoreClock/LPC_SYSCON->SYSAHBCLKDIV)/4000000-1)<<8;

return;
}

int adc0read(void){

int data;

LPC_ADC->CR |=0x01000000; //ADC Start now
while(!(LPC_ADC->DR0 & 0x80000000) );

data=((LPC_ADC->DR0 & 0x0000FFC0)>>6);
LPC_ADC->CR &= 0xF8FFFFFF; //stop ADC now

return(data);
}

adc.h

#ifndef ADC0_H_
#define ADC0_H_

extern void adc0_init(void);
extern int adc0read(void);

#endif /* ADC0_H_ */


uart.c
ベースのコードがあるエントリ:
「UART Rx回路を入れてみる」
「UART Txのプログラムを入れてみる。」

/*
* uart.c
*
* Created on: 2012/02/16
* Author: katsu
*/

#ifdef __USE_CMSIS
#include "LPC13xx.h"
#endif

#include
#include
#include "uart.h"



////
// Flag mask for UART_LSR register.
const uint32_t LSR_THRE = 0x20;
const uint32_t LSR_RDR = 0x01;

// Initialize UART module with specified baud-rate
void uart_init(uint32_t baudrate) {
// Divisor ratio
uint32_t Fdiv;

// Configure P1[7] as TXD output.
LPC_IOCON->PIO1_7 &= ~0x07; // FUNC=000 (GPIO)
LPC_IOCON->PIO1_7 |= 0x01; // FUNC=001 (TXD)

// Configure P1[6] as RXD input.
LPC_IOCON->PIO1_6 &= ~0x07; // FUNC=000 (GPIO)
LPC_IOCON->PIO1_6 |= 0x01; // FUNC=001 (RXD)

// Enable UART clock
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); // UART=1

// Enable UART peripheral clock
LPC_SYSCON->UARTCLKDIV = 0x01; // DIV=1

// Calculate baud rate divisor
Fdiv = (
SystemCoreClock // System clock frequency
* LPC_SYSCON->SYSAHBCLKDIV // AHB clock divider
) / (
LPC_SYSCON->UARTCLKDIV // UART clock divider
* 16 * baudrate // baud rate clock
);

// Set the baud rate divisor value
LPC_UART->LCR |= 0x80;
LPC_UART->DLM = Fdiv / 256;
LPC_UART->DLL = Fdiv % 256;
LPC_UART->LCR &= ~0x80;


// Configure UART module as
// 8 bit, 1 stop bit, no parity
// Enable and reset TX and RX FIFO.
LPC_UART->LCR = 0x03;
LPC_UART->FCR = 0x07;
}

// send a character via TXD
void uart_putc(const char c) {
// Wait for TX buffer empty
while (!(LPC_UART->LSR & LSR_THRE));
// Put a character
LPC_UART->THR = c;
}

// send a string via TXD
int uart_puts(const char *s) {
int n;
for (n = 0; *s; s++, n++) {
uart_putc(*s);
}
return n;
}

// receive a character via RXD
int uart_getc(void) {
// Wait for RX buffer valid
while (!(LPC_UART->LSR & LSR_RDR));
return LPC_UART->RBR;
}

// receive a string via RXD
char *uart_gets(char * const buf, const int size) {
int ch;
int n = 0;

while (n < size - 1) {
ch = uart_getc();
if (ch == '\r') {
// detected end of line
uart_puts("\r\n");
break;
}
uart_putc(ch);
buf[n++] = ch;
}
buf[n] = 0;
return buf;
}

uart.h

#ifndef UART_H_
#define UART_H_

extern void uart_init(uint32_t baudrate);
extern void uart_putc(const char c);
extern int uart_puts(const char *s);
extern int uart_getc(void) ;
extern char *uart_gets(char * const buf, const int size);

#endif /* UART_H_ */

LPC1343 UARTでADCを制御する 1/2

出来た事

UARTでADCを制御!!

開発Listへ戻る

動作結果
ハイパーターミナルからad0と入力するとAD変換の値が出てきてます!
その後、可変抵抗のボリュームを回して(電圧値を変えて)
もう一度ad0コマンドを入力しAD変換の値が変わっていることを確認しています。

機能ブロック図

動作フロー

  • ハイパーターミナルから"ad0"と入力する
  • LPC1343のAD0が変換実行!
  • 結果をハイパーターミナルに表示する

接続図

実際のものは、こんな感じです。
固定のためにユニバーサル基板を使っています。

次はコードの説明です。

USB-シリアル変換(UART)変換モジュール

秋月電子
FT232RL USBシリアル変換モジュール」を購入しました。

なんと950円!! 安い。

今までは
コレガのUSB-RS232C変換ケーブルを使っていましたが
信号の電圧が高いためにLPC1343に接続するには
レベル変換ICをつけなければならなかったのです。

今回はこのレベル変換ICがぶっ壊れたので購入です。


基板サイズは32x23mmですごく小さいです。



Driver!
ココから入手
(私の場合はwin7 64bit)

改造!
1)RTS#-CTS#ショート
2)DTR#-DSR#-DCD#ショート
 これらは他の記事を見てところ、ショートしなければならないようです。
3)TXD-RXDショート
 コレは動作確認のためのショートです。



動作確認!
1)まずドライバのインストール!
 付属の説明書のとおりですが、
 デバイスをUSBに差し込んで、
 マニュアルでDriver fileを解凍したフォルダを選択するだけです。

2)通信ソフトでの確認
 こいつはエレキジャックさんの記事参照です。
 私はHyper terminalで確認しました。


 問題なくどうさしました ^^


これからはこんな感じで接続して使っていきます。

ADCを使ってみる。

出来た事

1.ADCプロジェクトの作成 & 確認


予定では、I2Cを使ってEEPROMにアクセスしたい!
と思ってたんですけど,
仕様書見てもよくわかんないし、長いしで先にADCをやることにしました。
(今アマゾンに頼んでる本にI2Cのこと書いて有りそうだし。。)

基本的なLPC1343のADCの使い方!!

さて今回のコンセプトですが
1.ADC0を使う
2.出てきた答えはprintfで表示して確認する。
です。

printfを使うのでprojectはSemihostingを選択することに注意です。
CでもC++でもなくSemihosting C projectです

 一応エレキジャックさんのHello worldへのリンクはっときます

確認したコードは以下

#ifdef __USE_CMSIS
#include "LPC13xx.h"
#endif

#include
#include


__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

#include

int main(void) {
LPC_SYSCON->PDRUNCFG &= ~(0x1<<4); // See data sheet
LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<13); // See data sheet
LPC_IOCON->JTAG_TDI_PIO0_11 &= ~0x8F; // PIO0_11=Analog input
//ちょっと検討したら 0x8Fじゃなく0x9Fの方が良いことが判明。下で説明//

LPC_IOCON->JTAG_TDI_PIO0_11 |= 0x02; // PIO0_11=ADC0

LPC_ADC->CR |=0x00000001; // ADC0=on
//Clkdiv This time clk=4MHz (max=4.5MHz)
LPC_ADC->CR = *1; //修正2012.2.17
printf("%d\n",(LPC_ADC->DR0 & 0x0000FFC0)>>6);
LPC_ADC->CR &= 0xF8FFFFFF; //stop ADC now
}
return 0 ;
}

で、実験した回路がコレ
可変抵抗(ボリューム)がなかったので単純に抵抗で1/2分圧しただけです。


それで結果がコンソールに出たのがコレ

ADCが10bit精度で抵抗で1/2分圧してるだけなんで
値は512になって欲しかったんですが、ちょっとずれてますね。

確認のためにテスタで電圧を測ってみると
AD0 1.697V
3V3 3.149V
計算すると552になりますが表示は561か。。

ま、そんなもんなのかな。。


コードの解説です。
基本はNXPのSampleコードから持ってきてます。
(リンク先のLPC1343 Sample Projectから入手できます。)


LPC_SYSCON->PDRUNCFG &= ~(0x1<<4); // See data sheet
LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<13); // See data sheet

この2行はユーザマニュアルに書いてあるまんまです。
ココからダウンロード



LPC_IOCON->JTAG_TDI_PIO0_11 &= ~0x8F; // PIO0_11=Analog input
LPC_IOCON->JTAG_TDI_PIO0_11 |= 0x02; // PIO0_11=ADC0

こいつもPIN設定で書いてあるまんまなんですが
ただ、ピンのファンクションだけを変えればよいのではなく
Analog inputにしなければいけないところが注意です。


ここで、気づいてしまった。
なんだかNXPのサンプルコードはPIN設定がPull upになってますね。。。

LPC_IOCON->JTAG_TDI_PIO0_11 &= ~0x8F; // PIO0_11=Analog input

この記載を

LPC_IOCON->JTAG_TDI_PIO0_11 &= ~0x9F; // PIO0_11=Analog input

とするとプルアップが取れます。

すると。。。


コンソールのデータが期待値である512に
そして電圧も
AD0 1.573V
3V3 3.145V

サンプルコードはちょっとイカンかったようですね。

2012/2/14追記
よーくサンプルコードを見直してみると下の方に以下の記載がありました。

LPC_IOCON->JTAG_TDI_PIO0_11 = 0x02; // Select AD0 pin function

コレだと問題ないです。

なんで2種類の書き方してるのかはわからないんですが・・


気を取り直して次!

LPC_ADC->CR |=0x00000001; // ADC0=on
//Clkdiv This time clk=4MHz (max=4.5MHz)
LPC_ADC->CR = ((SystemCoreClock/LPC_SYSCON->SYSAHBCLKDIV)/4000000-1)<<8;

上の行はADCのオンオフコントロールです
次の行ですが、最初よくわからんかったですが
仕様書を見て理解しました。(20.5項)

ADCのクロックは4.5MHz以下にしなければならなくて
System clock(72MHz) / (CLKDIV+1)で計算されます。

で今回は4MHzになるようにしてみたということです。


最後!

LPC_ADC->CR |=0x01000000; //ADC Start now
while(LPC_ADC->DR0 & 0x80000000 );
printf("%d\n",(LPC_ADC->DR0 & 0x0000FFC0)>>6);
LPC_ADC->CR &= 0xF8FFFFFF; //stop ADC now


コレも仕様書をみるとわかるのですが

1行目はADCをStartさせる。
2行目は AD0のAD変換が完了するとDR0レジスタ31bitが1になります。それをチェック!
そしてprintfでコンソールに出力
一度ADCをとめます。



苦労話。。。(スルーOK)

実はADC、出来るのに2日以上かかってるんですよね。

ADCはエレキジャックさんのところで、
ざっと目次を見てもなかったので、自分でやりました。

サンプルコードを見るとなんだかややこしくって。。
バーストモードとか
LPC1343にある8個のADC全部をコントロールできるようにしてたりとか
とにかくサンプルコードは何でも出来る全部入りみたいな感じで。。

C言語もよくわかってない自分としては敷居高かったんです。

で、仕様書見てサンプルコード見てごちゃごちゃ自分で作ってると
LPC_IOCON->JTAG_TDI_PIO0_11 &= ~0x8F;
を入れてなかったんですね。
(PINの機能をADCにはセットしたがAnalog inputにしていなかった。。)

それでも、なぜだか値がでるんですよ。おかしな値が。。
それで余計にわからなくなって。。。

最終的に一つ一つサンプルコードと仕様書を追っていって
何とかできたんですが
振り返ってみるとたったコレだけに時間かかりすぎ!!!

まぁ開発ってのはそんなモンですけどね。。

*1:SystemCoreClock/LPC_SYSCON->SYSAHBCLKDIV)/4000000-1)<<8; printf("Hello World\n"); while(1) { LPC_ADC->CR |=0x01000000; //ADC Start now while(!(LPC_ADC->DR0 & 0x80000000

参考書籍

LPC1343開発日記もWeb上で動作が確認されたサンプルコードがないと
どうしても行き詰ってしまいます。

そこで、
参考書籍でも購入しようとAmazon検索して
2冊ほど購入。

ARM組み込みソフトウェア入門―記述例で学ぶ組み込み機器設計のためのシステム開発 (Design Wave Advanceシリーズ)

ARM組み込みソフトウェア入門―記述例で学ぶ組み込み機器設計のためのシステム開発 (Design Wave Advanceシリーズ)

こいつは・・・
私のような初心者にはまだまだ早い、"時代待ち"部類の本でした。

簡単な感想はエレガントな仕事をするために必要な本。
組み込みを行うときにARMの仕組みを知っておくと無駄がないぞう!的な
ある程度、仕事でバリバリやって効率化とか求められる人が参考にするものではないかと見受けました。
私のようなI2Cを動かすにはどうすんの?
見たいな人にはレベルが高すぎました。

いづれ使う日を夢見て"積読"です。


[rakuten:neowing-r:10415211:detail]
2冊目はまだ届いていません。
アマゾンの倉庫にはないようで時間がかかるようです。


この本は、LPC1343の実験ボードもついていて
I2CやADCに関しても解説があるようです。
(目次を見ると期待できそう!!)

しかし・・・
Amazon検索で LPC1343とか入力してもヒットしなかったこの本。
いろんなキーワードを入れてみてやっと見つけたのですが、
何を入れたかは覚えていません。
専門書は探すこと自体が難しい。

"LPC1343" "本" "参考書" とかでヒットすれば簡単なんですが。。。


あとは、初心者は内部機能を使うのにめっちゃ苦労するので

"LPC1343 ADC 使い方"
"LPC1343 I2C 使い方" とかそんなキーワードでも引っかかるようにして欲しいものです。

UART Rx回路を入れてみる。

出来た事

1.UART Rx プログラム追加と動作確認
2.UARTでコマンドを入れるとレスポンスするプログラムにモディファイ
(ハイパーターミナル設定注意)
3.C言語をちょっと学ぶ。(文字列の比較と分岐)

1.UART Rx プログラム追加と動作確認

まずはエレキジャックさんの記事の(8)をやっていきます。

LPC1100がLPC1343になるだけです。
問題なく出来ました(^^


2.UARTでコマンドを入れるとレスポンスするプログラムにモディファイ

ちょっとモディファイしてみます。

想定は
1.ハイパーターミナルであらかじめ決めたコマンドを入力
2.内部処理実施(内部データの参照など)
3.結果をハイパーターミナルに表示
という、実際にものを作る際に必要になりそうなものです。

で、今回は内部処理をとばして(2をとばして)1と3をやります。

ハイパーターミナルで
rd1と入力すると15
rd2と入力すると30
それ以外はna (not available)を返すというものです。
rd はreadという意味で個人的にFPGAなどをコントロールするときよく使ってます。

変更したコードは

#include //追加
// Main loop
int main(void) {
// Variable declaration
char line[40]; // Line buffer;
char *s; // return value
char ans[2];

// Initialize UART
uart_init(9600);
uart_puts("HELLO WORLD\r\n");

// Enter an infinite loop, just echo lines
while (1) {
// Get a line from UART
strcpy(s,"0");
s = uart_gets(line, sizeof line);
if (s) {
// Put a line into UART if valid

// 追加スタート
if(!strcmp(s,"rd1")){
strcpy(ans,"15");
}else if(!strcmp(s,"rd2")){
strcpy(ans,"30");
}else{
strcpy(ans,"na");
}
//追加エンド

uart_puts(ans);
uart_puts("\r\n");
}
}


すると
rd1と入力してリターンを押すと15
rd2と入力してリターンを押すと30
が返ってきます。
それ以外はna(not available)です。

赤い矢印がインプット
青い矢印がアウトプット(戻ってきた答え)です。


またコレをやっているときに
ハイパーターミナルの設定で少しはまりましたので注意
プロパティで以下のチェックをはずしておくことが必要です。


チェックがある場合は
リターンを押したときに復帰+改行("\r\n")になります
チェックがない場合は単純な復帰("\r")になります。

以下はエレキジャックさんのコードですが
"\r"でブレイクしてしまいます。

// receive a string via RXD
char *uart_gets(char * const buf, const int size) {
int ch;
int n = 0;

while (n < size - 1) {
ch = uart_getc();
if (ch == '\r') {
// detected end of line
uart_puts("\r\n");
break;
}
uart_putc(ch);
buf[n++] = ch;
}
buf[n] = 0;
return buf;
}

ですから設定でチェックがある場合は

起動して

"rd1"+リターンとすると

"rd1\r\n" と入力されたことになります。

"\r"でブレークしてbufに"rd1"が入りますが

次に"rd2"と入れた場合に"\n"が残ってますから
bufには"\nrd2"が入ってしまい問題になります。

ですから今回は設定を変更して"\n"を無くしてこのバグを回避しました。


3.C言語をちょっと学ぶ。(文字列の比較と分岐)

今回追加した部分は文字列を使った分岐です。

FPGAのとき(Velilog)はよくCase文を使ったので調べてみると
switch case文というのがありました。
しかし文字列には使えないということ(C言語では)

なのでif文を使いました。

FPGAでは書き方で回路規模やディレイが変わるのでタイミングが厳しいところは注意が必要なんですが
MCUは順次処理だからどうでもいいのかな。。

まぁ、出来たからコレで良いやと思います。


また比較も文字列のときは

strcmp

を使わなければならないとの事で。。

そして、strcmpを使うには

#include

をインクルードしなければならないということで。。

少しずつ勉強です。。