初めに
この記事の趣旨はLCDのコントラストをPWMで調整することにより部品点数を減らした上で
プログラム上から変更できることで後々の調整をしやすくするのを目標にしています。
コントラストをPWMで調整したい人ってあんまりいないのか日本語の情報なかったんですよね……
(私が見つけきれなかっただけかもしれませんが)
サンプルコード
バックライトLEDも制御するためのコードが混ざっていますが、自己責任でご自由にお使いください。
※ATmega328pを使用したArduinoでTimer1を使用しています。他の環境では未検証です。
# include <LiquidCrystal.h>
# define backlightPin 9
# define contrastPin 10
// LCD Pin (4bit mode)
# define rs 6
# define enable 7
# define d4 2
# define d5 3
# define d6 4
# define d7 5
// 関数プロトタイプ
void setBacklight (unsigned char);
void setContrast(unsigned char);
LiquidCrystal lcd(rs, enable, d4, d5, d6, d7);
void setup() {
// put your setup code here, to run once:
// LCD Data 4~7
pinMode(d4, OUTPUT);
pinMode(d5, OUTPUT);
pinMode(d6, OUTPUT);
pinMode(d7, OUTPUT);
// LCD RS,E
pinMode(rs, OUTPUT);
pinMode(enable, OUTPUT);
// LCD Contrast PWM
pinMode(contrastPin, OUTPUT);
// LCD BackLight PWM
pinMode(backlightPin, OUTPUT);
// Timer1 設定
// 全初期化
TCCR1A = B00000000;
TCCR1B = B00000000;
TCNT1 = B00000000;
// クロック16MHzでプリスケーラ1の場合40KHz
ICR1 = 399;
OCR1A = 399; // PWM 9 (100%)
OCR1B = 399; // PWM 10 (100%)
/*
PWM 9はコンペアマッチで立下がり
PWM 10はコンペアマッチで立ち上がり
PWMモードは高速PWM(TOPはICR1を使用)
プリスケーラは分周比1に設定
*/
TCCR1A |= B10110010;
TCCR1B |= B00011001;
// LCD SetUp cols 16 rows 2
lcd.begin(16, 2);
lcd.noAutoscroll();
lcd.print("hello, world");
}
unsigned char contrast = 0;
void loop() {
// put your main code here, to run repeatedly:
// setContrast(100);
setContrast(contrast++);
if (contrast > 100)contrast = 0;
delay(100);
}
// バックライト設定用関数
void setBacklight(unsigned char light) {
if (light > 100)light = 100;
int result = light * 4 - 1;
if (result < 0) result = 0;
OCR1A = result;
}
// コントラスト設定用関数
void setContrast(unsigned char param) {
if (param > 100)param = 100;
// int result = param * 4 - 1;
// if (result < 0) result = 0;
unsigned int result = 199 + (param * 2);
OCR1B = result;
}
簡単な説明
Arduino標準のPWMの場合PWM周波数が低いので画面にチラつきなどが発生するため
各種レジスタを直接弄って設定を変えています。
まず上部でdefineを使って各種ピンを定義しています。
ここでピンの指定を変更したらPWM周り以外は簡単に変更できます。
なお、LCDとの接続はHD44780の4bitモードで読み込みをしない前提なので最小限のI/O 6本を使用しています。
その下でコントラストとバックライトの明るさをセットするための関数のプロトタイプ宣言を行っています。
LCD関連の関数はLiquidCrystalライブラリの物なので詳しくはArduinoの日本語リファレンスにてご確認ください。
次はあらかじめ定義しておいたピンのモードを初期化します。
その後、Timer1の制御レジスタとカウンタを一度ゼロクリアします。
今回は40KHzでPWMを生成するのでICR1に399を設定します。
なお、計算式は
PWM周波数 = クロック周波数 / (分周比 * (1 + カウンタのカウントアップ上限))
なので
(16 * 10^6) / (1 * (1 + 399)) = 40000 Hz
となります。
ここから式を変形して
(16 * 10^6) / (40 * 10^3) = 400
(400 / 1) - 1 = 399
みたいな感じになります。
※高速PWMモードの場合はこの式ですが、位相基準PWMモードの場合分周比と一緒に
2をかける必要があるため詳しくはデータシートをご覧ください。
OCR1AとOCR1Bは初期は100%の出力(contrastPinについてはHi-Lo逆転)のために399を代入しています。
TCCR1AやTCCR1Bの詳しい事はデータシートをご確認ください。
setContrast関数は内部で出力を50~0%に制限しています。
(いい感じに薄い表示から濃い表示になってくれます)
最後に
私がテストしたLCDは20KHzだとノイズの所為か分かりませんが画面表示がずれたりしていたので、
PWMの周波数を上げたら解決しました。
多少なりとも誰かの参考になれば幸いです。