概要
はじめに
前回の記事「Arduino - ロータリスイッチの状態をA/D変換で取得する」と同様の回路を,PIC16F88とMPLAB XC8 C Compilerを使用して実装する方法を紹介します.
この開発例では,PIC16F88のA/D変換モジュールによるA/D変換と,AUSARTモジュールによる調歩同期式シリアル通信を行っています.
開発環境は下記のとおりです.
PIC |
PIC16F88-I/P |
MPLAB X IDE |
MPLAB X IDE v2.26 |
MPLAB XC8 |
MPLAB XC8 C Compiler v1.32 |
PICkit 2 |
MPLAB X IDEを使用して書込み |
通信仕様
通信仕様は下表のとおりです.
本記事では詳細は説明しませんが,今回はUSBシリアル変換モジュールを経由してPICとPCとの間で調歩同期式シリアル通信を行いました.
調歩同期式シリアル通信について調べる場合は,「RS-232C」や「UART」をキーワードに検索してみてください.
ボーレート |
9,600 bps |
データビット |
8 bit |
パリティビット |
なし |
ストップビット |
1 bit |
フロー制御 |
なし |
回路
回路図
PDFファイルにて公開します.
PICkit 2を使用してICSP (In Circuit Serial Programming)と電源供給を行うことを前提とした回路です.
今回は,これをブレッドボード上に組んで動作を確認しました.
ロータリスイッチ SW1の共通接点Aは,グランドに接続されています.
一方,PIC16F88のAN0ピンは,常にSW1の選択接点1に接続されています.
スイッチを回転させると,合成抵抗の分圧比が変化し,アナログ入力ピンに印加される電圧が変化します.
この変化を読み取ることで,SW1の状態を取得できます.
仮に共通接点Aがいずれの選択端子にも接続されていない状態になっても,AN0ピンは抵抗 R1でプルアップされている状態となり,ハイインピーダンスにはなりません.
回路部品
下表は使用部品表です.
参考単価をクリックすると,秋月電子通商のページに飛びます.
「互換品」と記載されているリンクについては,互換性があると考えられる部品のページに飛びます.
ただし,私が互換性および動作を確認したわけではありませんので,ご注意ください.
番号 |
部品名 |
型番 |
数量 |
参考単価 |
U1 |
PICマイコン |
Microchip PIC16F88-I/P |
1 |
250円 |
U2 |
USBシリアル変換 モジュールキット |
秋月電子通商 AE-UM232R |
1 |
800円 |
X1 |
セラロック |
村田製作所 20MHz |
1 |
35円 |
SW1 |
ロータリスイッチ |
1回路12接点 ノンショーティングタイプ |
1 |
150円 (互換品) |
R1 |
炭素皮膜抵抗 |
各社 1/4W 10kΩ |
1 |
1円 (互換品) |
R2, R11 |
炭素皮膜抵抗 |
各社 1/4W 4.7kΩ |
2 |
1円 (互換品) |
R3 |
炭素皮膜抵抗 |
各社 1/4W 470Ω |
1 |
1円 (互換品) |
R4 |
炭素皮膜抵抗 |
各社 1/4W 680Ω |
1 |
1円 (互換品) |
R5 |
炭素皮膜抵抗 |
各社 1/4W 820Ω |
1 |
1円 (互換品) |
R6 |
炭素皮膜抵抗 |
各社 1/4W 1kΩ |
1 |
1円 (互換品) |
R7 |
炭素皮膜抵抗 |
各社 1/4W 1.2kΩ |
1 |
1円 (互換品) |
R8 |
炭素皮膜抵抗 |
各社 1/4W 1.5kΩ |
1 |
1円 (互換品) |
R9 |
炭素皮膜抵抗 |
各社 1/4W 2.2kΩ |
1 |
1円 (互換品) |
R10 |
炭素皮膜抵抗 |
各社 1/4W 3kΩ |
1 |
1円 (互換品) |
R12 |
炭素皮膜抵抗 |
各社 1/4W 8.2kΩ |
1 |
1円 (互換品) |
R13 |
炭素皮膜抵抗 |
各社 1/4W 15kΩ |
1 |
1円 (互換品) |
|
その他 |
リード線など |
適量 |
|
回路製作例
ロータリスイッチ周辺の配線については,前回の記事の「回路製作例」で紹介しています.
プログラム
A/D変換値からロータリスイッチの状態を取得する方法
まず,ロータリスイッチの各状態における,AN0ピンへの印加電圧を計算してみましょう.
計算結果を下表に示します.
下表から,例えば選択接点2の場合は,AN0ピンへの印加電圧が0.455Vになることがわかります.
PIC16F88のA/D変換の分解能は10bit(0~1023)ですから,A/D変換値は93になると考えられます.
ただし,電源電圧や抵抗値の公差により,各値は多少変動します.
これらの計算結果を基に,A/D変換値と閾値を比較することで,ロータリスイッチの状態を割り出します.
例えば,選択接点が3以下か4以上かを調べるためには,各状態におけるA/D変換値(201と302)の中間値(252)を閾値にします.
このような比較処理を繰り返すことで.選択接点が特定できます.
ロータリスイッチの選択接点とアナログ入力ピンへの印加電圧の関係 |
選択接点 |
印加電圧 [V] |
A/D変換値(10bit) |
1 |
0.000 |
0 |
2 |
0.455 |
93 |
3 |
0.983 |
201 |
4 |
1.477 |
302 |
5 |
1.936 |
396 |
6 |
2.351 |
481 |
7 |
2.734 |
560 |
8 |
3.130 |
641 |
9 |
3.491 |
715 |
10 |
3.841 |
787 |
11 |
4.175 |
855 |
12 |
4.459 |
910 |
main.c
下記は,ソースファイル main.cです.
このほかに,「16F88 XC8開発例 - 調歩同期式シリアル通信(AUSARTモジュール)」に掲載している,uart.cとuart.hが必要です.
A/D変換値からロータリスイッチの状態を取得する,getRotarySwStatus()関数を作成しました.
これは,前回の記事で紹介した,Arduinoのスケッチから移植した関数です.
復帰値1~12でロータリスイッチの状態を,復帰値0で取得エラーを示します.
getRotarySwStatus()関数内の条件分岐処理がif文の入れ子構造になっているのは,ロータリスイッチの状態によって関数内の処理時間が変動しないようにしたかったためです.
この関数では,ロータリスイッチがいずれの状態であっても条件分岐処理が3回以内になっています.
よりスマートなやり方があるのだとは思いますが….
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | #include <xc.h>
#include <stdio.h>
#include "uart.h"
#define _XTAL_FREQ 20000000 // 20MHz
#define PIN_ROTARYSW 0
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = ON
#pragma config BOREN = ON
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CCPMX = RB3
#pragma config CP = OFF
#pragma config FCMEN = OFF
#pragma config IESO = OFF
void setADCChannel(unsigned char channel);
unsigned int readADCValue( void );
unsigned char getRotarySwStatus(unsigned int sw_inp);
void main( void )
{
unsigned int sw_inp;
unsigned char sw_pos;
PORTA = 0x00;
PORTB = 0x00;
TRISA = 0b00000001;
TRISB = 0b00000100;
ANSEL = 0b00000001;
ADCON0 = 0b10000001;
ADCON1 = 0b11000000;
initUART();
while (1){
setADCChannel(PIN_ROTARYSW);
__delay_us(50);
sw_inp = readADCValue();
printf ( "AN0: %d\r\n" , sw_inp);
sw_pos = getRotarySwStatus(sw_inp);
printf ( "Status: %d\r\n" , sw_pos);
__delay_ms(250);
}
}
void setADCChannel(unsigned char channel)
{
ADCON0 &= 0b11000111;
ADCON0 |= (channel << 3);
}
unsigned int readADCValue( void )
{
GO_nDONE = 0b1;
while (GO_nDONE);
return ((ADRESH << 8) + ADRESL);
}
unsigned char getRotarySwStatus(unsigned int sw_inp)
{
if (sw_inp < 349){
if (sw_inp < 147){
if (sw_inp < 47){
return 1;
}
else {
return 2;
}
}
else {
if (sw_inp < 252){
return 3;
}
else {
return 4;
}
}
}
else if (sw_inp < 677){
if (sw_inp < 520){
if (sw_inp < 438){
return 5;
}
else {
return 6;
}
}
else {
if (sw_inp < 599){
return 7;
}
else {
return 8;
}
}
}
else if (sw_inp < 967){
if (sw_inp < 820){
if (sw_inp < 750){
return 9;
}
else {
return 10;
}
}
else {
if (sw_inp < 883){
return 11;
}
else {
return 12;
}
}
}
return 0;
}
|
製品紹介
SparkFun
売り上げランキング: 369,705