2018年7月16日月曜日

キャラクタ液晶に天気予報を表示する

暑い・・・。暑すぎる。

キャラクタ液晶の使い道を考えていた。
暑くて、天気予報が知りたくなった。

早速結果からだけど、こんな感じ


1. 天気予報を取得する

livedoorの天気予報サービスを利用させてもらう。
http://weather.livedoor.com/weather_hacks/webservice

都市は「東京」なので「http://weather.livedoor.com/forecast/webservice/json/v1?city=130010

JSONで応答してくれるみたい。
[forecasts][0][telop]に[晴のち曇り]
[forecasts][0][temperature][max][celsius]に[最高気温]

linuxボードにpythonとか入っていないので、awkとsedで頑張る!



2. 天気アイコンをアニメーションしたい

外字(CGRAM)は8種類しかないけれど、書き込むと表示中のものも変更された!
ということは、動的に変更できて、なんちゃってアニメーションできそう。


3. 表示

上段に「サイコウ キオン:●●°C」
下段に「テンキ:■■■■■」
■部分は、例えば「晴のち曇」なら
「晴アイコン」「ハレ」「→」「曇アイコン」「クモリ」

JSON出力はUnicodeで「晴のち曇」は「"\u6674\u306e\u3061\u66c7"」となる。
「のち」なら「→」、「時々」なら「/」とした。
外字は

外字は1s毎に書き換えを行い、アニメーションしてるっぽくした。
また、1時間毎に天気予報を更新する。
(今回は実験なので、この間隔にしたけど、長期に使う場合には、
 利用規約確認したり、迷惑かからないように12時間とか24時間とかのほうがいいかも)

ソース

#!/bin/sh
CDEVNAME=/dev/PicClcdDriver0
SYSDEV=/sys/bus/spi/drivers/PicClcdDriver/spi0.1/
CMD_CLEAR=lcd_clear
CMD_SETCGRAM=lcd_set_cgram
CMD_SETDDRAM=lcd_set_ddram
#URL
TENKI_API="http://weather.livedoor.com/forecast/webservice/json/v1?city=130010"
#debug
#DEBUG_FLG=1
#外形文字(天気アイコン)
HARE0=00411040E04110400
HARE1=004150A110A150400
AME0=111150E1F04140800
AME1=111040E1F04050200
KUMORI0=2000A1500150A0000
KUMORI1=20A150A000A150A00
KAMINARI0=30408180E03020400
KAMINARI1=30408100A04081000
YUKI0=40812050208140800
YUKI1=40205020814090200
#Unicode
U_HARE=6674
U_NO=306E
U_CHI=3061
U_AME=96E8
U_KUMORI=66C7
U_KAMINARI=96F7
U_UKI=96EA
U_TOKI=6642
U_DOKI=3005
#CGRAM
echo $HARE0 > $SYSDEV/$CMD_SETCGRAM
echo $AME0 > $SYSDEV/$CMD_SETCGRAM
echo $KUMORI0 > $SYSDEV/$CMD_SETCGRAM
echo $KAMINARI0 > $SYSDEV/$CMD_SETCGRAM
echo $YUKI0 > $SYSDEV/$CMD_SETCGRAM
while :
do
#最高気温・天気取得
RETTENKI=`wget -O - $TENKI_API | awk -Fforecasts '{print $2}' | awk -Flocation '{print $1}'`
# LCD クリア
echo > $SYSDEV$CMD_CLEAR
# 温度表示
if [ "$DEBUG_FLG" = "1" ]; then
MAXTEMP=`cat test2.txt | awk -Fmax '{print $2}' | awk -Fcelsius '{print $2}' | awk -Ffahrenheit '{print $1}' | sed -e 's/[:,"]//g'`
else
MAXTEMP=`echo $RETTENKI | awk -Fmax '{print $2}' | awk -Fcelsius '{print $2}' | awk -Ffahrenheit '{print $1}' | sed -e 's/[:,"]//g'`
fi
echo 最高気温:$MAXTEMP
#サイコウ キオン:
echo -ne "\xBB" > $CDEVNAME
echo -ne "\xB2" > $CDEVNAME
echo -ne "\xBA" > $CDEVNAME
echo -ne "\xB3" > $CDEVNAME
echo -ne "\xA0" > $CDEVNAME
echo -ne "\xB7" > $CDEVNAME
echo -ne "\xB5" > $CDEVNAME
echo -ne "\xDD" > $CDEVNAME
echo -ne "\x3A" > $CDEVNAME
echo -n $MAXTEMP > $CDEVNAME
echo -en "\xdf" > $CDEVNAME
echo -n "C " > $CDEVNAME
#2行目に移動
echo -n 40 > $SYSDEV/$CMD_SETDDRAM
#テンキ:
echo -ne "\xC3" > $CDEVNAME
echo -ne "\xDD" > $CDEVNAME
echo -ne "\xB7" > $CDEVNAME
echo -ne "\x3A" > $CDEVNAME
# 天気
if [ "$DEBUG_FLG" = "1" ]; then
WEATHER=`cat test2.txt | awk -Ftelop '{print $2}' | awk -Fdate '{print $1}' | sed -e 's/[:,"u]//g' | sed 's/\\\\/ /g' | tr '[a-z]' '[A-Z]'`
else
WEATHER=`echo $RETTENKI | awk -Ftelop '{print $2}' | awk -Fdate '{print $1}' | sed -e 's/[:,"u]//g' | sed 's/\\\\/ /g' | tr '[a-z]' '[A-Z]'`
fi
echo $WEATHER
for i in $WEATHER
do
echo $i
if [ "$i" = "$U_HARE" ]; then
echo 晴
echo -ne "\x08" > $CDEVNAME
echo -ne "\xCA" > $CDEVNAME
echo -ne "\xDA" > $CDEVNAME
elif [ "$i" = "$U_AME" ]; then
echo 雨
echo -ne "\x09" > $CDEVNAME
echo -ne "\xB1" > $CDEVNAME
echo -ne "\xD2" > $CDEVNAME
elif [ "$i" = "$U_KUMORI" ]; then
echo 曇
echo -ne "\x0A" > $CDEVNAME
echo -ne "\xB8" > $CDEVNAME
echo -ne "\xD3" > $CDEVNAME
echo -ne "\xD8" > $CDEVNAME
elif [ "$i" = "$U_KAMINARI" ]; then
echo 雷
echo -ne "\x0B" > $CDEVNAME
echo -ne "\xB6" > $CDEVNAME
echo -ne "\xD0" > $CDEVNAME
echo -ne "\xC5" > $CDEVNAME
echo -ne "\xD8" > $CDEVNAME
elif [ "$i" = "$U_UKI" ]; then
echo 雪
echo -ne "\x0C" > $CDEVNAME
echo -ne "\xD5" > $CDEVNAME
echo -ne "\xB7" > $CDEVNAME
elif [ "$i" = "$U_NO" ]; then
echo の
echo -ne "\x7E" > $CDEVNAME
elif [ "$i" = "$U_TOKI" ]; then
echo 時
echo -ne "\x2F" > $CDEVNAME
fi
done
#echo -ne "\x09" > $CDEVNAME
#echo -ne "\x0A" > $CDEVNAME
#echo -ne "\x0B" > $CDEVNAME
#echo -ne "\x0C" > $CDEVNAME
#echo -ne "\x7E" > $CDEVNAME
OLD_DT=`date '+%Y%m%d %H'`
NEW_DT=`date '+%Y%m%d %H'`
echo $OLD_DT
while [ "$OLD_DT" = "$NEW_DT" ]
do
NEW_DT=`date '+%Y%m%d %H'`
#echo $NEW_DT
sleep 1
echo $HARE1 > $SYSDEV/$CMD_SETCGRAM
echo $AME1 > $SYSDEV/$CMD_SETCGRAM
echo $KUMORI1 > $SYSDEV/$CMD_SETCGRAM
echo $KAMINARI1 > $SYSDEV/$CMD_SETCGRAM
echo $YUKI1 > $SYSDEV/$CMD_SETCGRAM
sleep 1
echo $HARE0 > $SYSDEV/$CMD_SETCGRAM
echo $AME0 > $SYSDEV/$CMD_SETCGRAM
echo $KUMORI0 > $SYSDEV/$CMD_SETCGRAM
echo $KAMINARI0 > $SYSDEV/$CMD_SETCGRAM
echo $YUKI0 > $SYSDEV/$CMD_SETCGRAM
done
echo $NEW_DT
done
view raw weather.sh hosted with ❤ by GitHub

使いそびれたパラレルキャラクタ液晶のSPI化(2/2)

前回からのつづき
制御用のFON2405E(LEDE・Openwrt)向けドライバ作成

1. SPI仕様

[0x01][コントラスト] ※コントラストは0x00〜0x06
[0x02][コマンド]  ※ RS=0 でLCDに出力
[0x03][データ]   ※ RS=1 でLCDに出力

http://akizukidenshi.com/download/ds/sunlike/SD1602HULB-XA-G-G.PDF
http://219.117.208.26/~saka/ham/LCD2/

2. ドライバ仕様

基本的には、MCP23S09の時と同じ。
キャラクタデバイスとして[/dev/ PicClcdDriver0]が作成される。
これに表示したい内容を流しこめばOK
一方で、各種制御は[/sys/bus/spi/drivers/PicClcdDriver/spi0.1/]に
lcd_clear:Clear Display(全表示クリア)
lcd_set_cgram:Set CGRAM address
lcd_set_ddram:Set DDRAM address
が作成される

3. 動作

insmod pic_clcd.ko
echo > /sys/bus/spi/drivers/PicClcdDriver/spi0.1/lcd_clear
echo -n HelloWorld! >  /dev/ PicClcdDriver0

英数字以外 例えば 「イ」とか
echo -ne "\xB2" > /dev/ PicClcdDriver0

外字CGRAM
0番目に「晴?」アイコン
echo 00411040E04110400 > /sys/bus/spi/drivers/PicClcdDriver/spi0.1/lcd_set_cgram



ドライバソースコード
/*
* pic_cled.c
*
* Created on: 2018/07/08
* Author: adeno
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/uaccess.h> //copy_from_user
#include <linux/gpio.h>
#include <linux/spi/spi.h>
MODULE_AUTHOR("Adeno");
MODULE_LICENSE("GPL v2");
//=======================================================================================
/* ドライバ */
#define DRV_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */
#define DRV_DEVNAME "PicClcdDriver" /* このデバイスドライバの名称 */
#define DRV_MAJOR 0 /* メジャー番号だが自動設定なので0 */
#define DRV_MINOR 0 /* マイナー番号のベース番号 */
#define DRV_GPIO_MAPNAME "pcd_gpio_map"
/* SPI PIC設定 */
#define SPCD_PACKET_SIZE 1
const uint8_t SPCD_LCD_PWM = 0x01;
const uint8_t SPCD_LCD_CMD = 0x02;
const uint8_t SPCD_LCD_DATA = 0x03;
const uint8_t SPCD_LCD_CMD_CLEARDISPLAY = 0b00000001;
const uint8_t SPCD_LCD_CMD_RETURNHOME = 0b00000010;
const uint8_t SPCD_LCD_CMD_SETCGRAM = 0b01000000;
const uint8_t SPCD_LCD_CMD_SETDDRAM = 0b10000000;
//=======================================================================================
/* ドライバ */
static int _spcd_major = DRV_MAJOR;
static int _spcd_minor = DRV_MINOR;
/* SPI */
struct drvdata {
struct spi_device *spi;
struct mutex lock;
unsigned char tx[SPCD_PACKET_SIZE];
unsigned char rx[SPCD_PACKET_SIZE];
struct spi_transfer xfer;
struct spi_message msg;
dev_t md_dev;
struct class *drv_class;
struct cdev *drv_cdev_array;
} ____cacheline_aligned;
static struct drvdata spcd;
static struct spi_board_info spcd_info = {
.modalias = "spcd",
.max_speed_hz = 1000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_3,
};
static struct spi_device_id spcd_id[] = {
{ "spcd", 0 },
{ },
};
MODULE_DEVICE_TABLE(spi, spcd_id);
/* Parameters Setting */
static int gpiono = 9;
static int show_debug = 0;
//static int hexmode = 0;
//=======================================================================================
/* プロトタイプ宣言 */
static unsigned int spcd_set_value( struct drvdata *data,unsigned int v);
static void spi_remove_device(struct spi_master *master, unsigned int cs);
static int spcd_probe(struct spi_device *spi);
static int spcd_remove(struct spi_device *spi);
static int spcd_open(struct inode *inode, struct file *filep);
static int spcd_release(struct inode *inode, struct file *filep);
static ssize_t spcd_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos);
static int spcd_register_dev(void);
static int spcd_init(void);
static void spcd_exit(void);
//=======================================================================================
/* SPIデバイス */
static struct spi_driver spcd_driver = {
.driver = {
.name = DRV_DEVNAME,
.owner = THIS_MODULE,
},
.id_table = spcd_id,
.probe = spcd_probe,
.remove = spcd_remove,
};
/* キャラクタデバイス */
struct file_operations spcd_fops = {
.open = spcd_open,
.release = spcd_release,
.write = spcd_write,
};
//=======================================================================================
static int lcd_clear_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
spcd_set_value(drd,SPCD_LCD_CMD);
spcd_set_value(drd,SPCD_LCD_CMD_CLEARDISPLAY);
// spcd_set_value(drd,SPCD_LCD_FIN);
return size;
}
static DEVICE_ATTR(lcd_clear, S_IWUSR|S_IWGRP, NULL, lcd_clear_store );
static int lcd_set_cgram_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
//CharNo Line(0-7)
//[1] [2]x8
int b[9],i;
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
if(size >= 17){
if(buf[0] >='0' && buf[0] <= '9') b[0] = buf[0]-'0';
b[0] = SPCD_LCD_CMD_SETCGRAM | (((b[0] & 0b111) << 3) & 0b111000);
if(show_debug) printk(KERN_INFO "LCD SET CG Adr size=%d,C=%d\n",size,b[0]);
// /*if(show_debug)*/ printk(KERN_INFO "LCD SET CG Adr output=%d\n",b[0]);
spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,b[0]);
for(i=0; i<8; i++){
if(buf[i*2+1] >='0' && buf[i*2+1] <= '9') b[i] = (buf[i*2+1]-'0') * 0x10;
else if(buf[i*2+1] >='A' && buf[i*2+1] <= 'F') b[i] += (buf[i*2+1]-'A'+0xA) * 0x10;
else if(buf[i*2+1] >='a' && buf[i*2+1] <= 'f') b[i] += (buf[i*2+1]-'A'+0xA) * 0x10;
if(buf[i*2+2] >='0' && buf[i*2+2] <= '9') b[i] += (buf[i*2+2]-'0');
else if(buf[i*2+2] >='A' && buf[i*2+2] <= 'F') b[i] += (buf[i*2+2]-'A'+0xA);
else if(buf[i*2+2] >='a' && buf[i*2+2] <= 'f') b[i] += (buf[i*2+2]-'A'+0xA);
spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,b[i]);
}
// spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,0b10); //ホームに
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,buf[0]-'0');
//
//
//
// if((buf[0] >='0' && buf[0] <= '9') && (buf[1] >='0' && buf[1] <= '9')){
// int cno = buf[0]-'0';
// int lno = buf[1]-'0';
// int b = 0x40 | (((cno & 0b111) << 3) | (lno & 0b111));
// /*if(show_debug)*/ printk(KERN_INFO "LCD SET CG Adr size=%d,C=%d,L=%d,output=%d\n",size,cno,lno,b);
//
// spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,b);
//// spcd_set_value(drd,SPCD_LCD_FIN);
//
// //debug
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b00000);
//// spcd_set_value(drd,SPCD_LCD_FIN);
// }
}
return size;
}
static DEVICE_ATTR(lcd_set_cgram, S_IWUSR|S_IWGRP, NULL, lcd_set_cgram_store );
static int lcd_set_ddram_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
//Adr
//[2]
int b;
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
if(size >= 1){
if(buf[0] >='0' && buf[0] <= '9') b = (buf[0]-'0') * 0x10;
else if(buf[0] >='A' && buf[0] <= 'F') b += (buf[0]-'A'+0xA) * 0x10;
else if(buf[0] >='a' && buf[0] <= 'f') b += (buf[0]-'A'+0xA) * 0x10;
if(buf[1] >='0' && buf[1] <= '9') b += (buf[1]-'0');
else if(buf[1] >='A' && buf[1] <= 'F') b += (buf[1]-'A'+0xA);
else if(buf[1] >='a' && buf[1] <= 'f') b += (buf[1]-'A'+0xA);
/*if(show_debug)*/ printk(KERN_INFO "LCD SET DD Adr size=%d,C=%d\n",size,(b | SPCD_LCD_CMD_SETDDRAM));
spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,(b | SPCD_LCD_CMD_SETDDRAM));
}
return size;
}
static DEVICE_ATTR(lcd_set_ddram, S_IWUSR|S_IWGRP, NULL, lcd_set_ddram_store );
static int lcd_contrast_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
if(size > 0){
if(show_debug) printk(KERN_INFO "Change LCD Contrast %d,%c\n", size,buf[0]);
spcd_set_value(drd,SPCD_LCD_PWM);
switch(buf[0]){
case '0':
spcd_set_value(drd,0x00);
break;
case '1':
spcd_set_value(drd,0x01);
break;
case '2':
spcd_set_value(drd,0x02);
break;
case '3':
spcd_set_value(drd,0x03);
break;
case '4':
spcd_set_value(drd,0x04);
break;
case '5':
spcd_set_value(drd,0x05);
break;
case '6':
spcd_set_value(drd,0x06);
break;
default:
spcd_set_value(drd,0x03);
break;
}
}
return size;
}
static DEVICE_ATTR(lcd_contrast, S_IWUSR|S_IWGRP, NULL, lcd_contrast_store );
static unsigned int spcd_set_value( struct drvdata *data,unsigned int v)
{
unsigned int r = 0;
mutex_lock( &data->lock );
data->tx[0] = v;
if( spi_sync( data->spi, &data->msg) ) {
if(show_debug) printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
usleep_range(1000,2000);
mutex_unlock(&data->lock);
return r;
}
/**
* SPIデバイスの削除
*/
static void spi_remove_device(struct spi_master *master, unsigned int cs)
{
struct device *dev;
char str[128];
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
if(show_debug) printk(KERN_INFO "[spi_remove_device] %s\n",str);
// SPIデバイスを探す
dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
// あったら削除
if( dev ){
if(show_debug) printk(KERN_INFO "Delete %s\n", str);
device_del(dev);
}
}
/**
* SPI通信初期化
*/
static int spcd_probe(struct spi_device *spi)
{
// struct mcp_drvdata *data;
int retval;
if(show_debug) printk(KERN_INFO "spcd spi probe\n");
/* SPIを設定する */
spi->max_speed_hz = spcd_info.max_speed_hz;
spi->mode = spcd_info.mode;
spi->bits_per_word = 8;
if( spi_setup( spi ) ) {
printk(KERN_ERR "spi_setup returned error\n");
return -ENODEV;
}
spcd.spi = spi;
mutex_init( &spcd.lock );
spcd.xfer.tx_buf = spcd.tx;
spcd.xfer.rx_buf = 0;//data->rx;
spcd.xfer.bits_per_word = 8;
spcd.xfer.len = SPCD_PACKET_SIZE;
spcd.xfer.cs_change = 0;
spcd.xfer.delay_usecs = 0;
spcd.xfer.speed_hz = 1000000;
spi_message_init_with_transfers( &spcd.msg, &spcd.xfer, 1 );
spi_set_drvdata( spi, &spcd );
mutex_lock( &spcd.lock );
spcd.tx[0] = 0x00;
if( spi_sync( spcd.spi, &spcd.msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&spcd.lock);
retval = device_create_file( &spi->dev, &dev_attr_lcd_clear );
if(retval) {
printk(KERN_ERR "failed to add lcd_clear attribute\n" );
}
retval = device_create_file( &spi->dev, &dev_attr_lcd_contrast );
if(retval) {
printk(KERN_ERR "failed to add lcd_contrast attribute\n" );
}
retval = device_create_file( &spi->dev, &dev_attr_lcd_set_cgram );
if(retval) {
printk(KERN_ERR "failed to add lcd_set_cgram attribute\n" );
}
retval = device_create_file( &spi->dev, &dev_attr_lcd_set_ddram );
if(retval) {
printk(KERN_ERR "failed to add lcd_set_ddram attribute\n" );
}
return 0;
}
/**
* SPI通信終了
*/
static int spcd_remove(struct spi_device *spi)
{
if(show_debug) printk(KERN_INFO "[spcd spi_remove]\n");
struct drvdata *drd = spi_get_drvdata(spi);
mutex_lock( &drd->lock );
drd->tx[0] = 0x00;
if( spi_sync( drd->spi, &drd->msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&drd->lock);
device_remove_file( &spi->dev, &dev_attr_lcd_clear);
device_remove_file( &spi->dev, &dev_attr_lcd_contrast);
device_remove_file( &spi->dev, &dev_attr_lcd_set_cgram);
device_remove_file( &spi->dev, &dev_attr_lcd_set_ddram);
spi_set_drvdata(drd->spi, NULL);
drd->spi = NULL;
mutex_destroy(&spcd.lock);
if(gpiono != 0) gpio_free(gpiono);
return 0;
}
/**
* デバイスオープン時の処理
*/
static int spcd_open(struct inode *inode, struct file *filep)
{
if(show_debug) printk(KERN_INFO "[spcd_open]\n");
filep->private_data = &spcd;
return 0;
}
/**
* デバイスクローズ時の処理
*/
static int spcd_release(struct inode *inode, struct file *filep)
{
if(show_debug) printk(KERN_INFO "[spcd_release]\n");
struct drvdata *drd = filep->private_data;
if ((drd == NULL) || (drd->spi == NULL))
return -ENODEV;
filep->private_data = NULL;
return 0;
}
/**
* デバイス書き込み処理
*/
static ssize_t spcd_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos)
{
char cvalue;
// int i;
struct drvdata *drd = filep->private_data;
if ((drd == NULL) || (drd->spi == NULL))
return -ENODEV;
// struct mcp_drvdata *data = (struct mcp_drvdata *)dev_get_drvdata(filep->private_data);
if(count > 0) {
if(gpiono != 0) gpio_set_value(gpiono,1);
if(copy_from_user( &cvalue, buf, sizeof(char) )) {
return -EFAULT;
}
spcd_set_value(drd,SPCD_LCD_DATA);
spcd_set_value(drd,cvalue);
// spcd_set_value(drd,SPCD_LCD_FIN);
// if((cvalue >=0) && (cvalue <= 9)) spcd_set_value(drd,cvalue);
// else if(('0' <= cvalue) && (cvalue <= '9')) {
// spcd_set_value(drd,0x03);
// spcd_set_value(drd,cvalue);
// spcd_set_value(drd,0x00);
// }
// else{
// if(hexmode){
// if(('A' <= cvalue) && (cvalue <= 'F')) spcd_set_value(drd,cvalue - 'A' + 10);
// else if(('a' <= cvalue) && (cvalue <= 'f')) spcd_set_value(drd,cvalue - 'a' + 10);
// }
// else if(show_debug) printk(KERN_ALERT "Can not display %d\n", cvalue );
// }
if(gpiono != 0) gpio_set_value(gpiono,0);
return sizeof(char);
}
return 0;
}
/**
* デバイスドライバをカーネルに登録
*/
static int spcd_register_dev(void)
{
int retval;
// dev_t dev;
size_t size;
int i;
/* 空いているメジャー番号を使ってメジャー&
マイナー番号をカーネルに登録する */
retval = alloc_chrdev_region(
&spcd.md_dev, /* 結果を格納するdev_t構造体 */
DRV_MINOR, /* ベースマイナー番号 */
DRV_NUM_DEVS, /* デバイスの数 */
DRV_DEVNAME /* デバイスドライバの名前 */
);
if( retval < 0 ) {
printk(KERN_ERR "alloc_chrdev_region failed.\n" );
return retval;
}
_spcd_major = MAJOR(spcd.md_dev);
/* デバイスクラスを作成する */
spcd.drv_class = class_create(THIS_MODULE,DRV_DEVNAME);
if(IS_ERR(spcd.drv_class))
return PTR_ERR(spcd.drv_class);
/* cdev構造体の用意 */
size = sizeof(struct cdev) * DRV_NUM_DEVS;
spcd.drv_cdev_array = (struct cdev*)kmalloc(size, GFP_KERNEL);
/* デバイスの数だけキャラクタデバイスを登録する */
/* ただし7セグLEDは1個しかない */
for( i = 0; i < DRV_NUM_DEVS; i++ ) {
dev_t devno = MKDEV(_spcd_major, _spcd_minor+i);
/* キャラクタデバイスとしてこのモジュールをカーネルに登録する */
cdev_init(&(spcd.drv_cdev_array[i]), &spcd_fops);
spcd.drv_cdev_array[i].owner = THIS_MODULE;
if( cdev_add( &(spcd.drv_cdev_array[i]), devno, 1) < 0 ) {
/* 登録に失敗した */
printk(KERN_ERR "cdev_add failed minor = %d\n", _spcd_minor+i );
}
else {
/* デバイスノードの作成 */
device_create(
spcd.drv_class,
NULL,
devno,
NULL,
DRV_DEVNAME"%u",_spcd_minor+i
);
}
}
return 0;
}
/**
* モジュールの初期化処理
*/
static int spcd_init(void)
{
int retval;
int i;
/* 開始のメッセージ */
printk(KERN_INFO "%s loading...\n", DRV_DEVNAME );
if(gpiono != 0){
/* GPIOレジスタがマップ可能か調べる */
retval = gpio_request_one(gpiono, GPIOF_OUT_INIT_LOW, DRV_GPIO_MAPNAME);
if (retval) {
printk(KERN_ERR "Unable to request GPIOs: %d\n", retval);
return retval;
}
for( i=0; i<10; i++ ) {
gpio_set_value(gpiono,1);
msleep(10);
gpio_set_value(gpiono,0);
msleep(10);
}
}
/* デバイスドライバをカーネルに登録 */
retval = spcd_register_dev();
if( retval != 0 ) {
printk( KERN_ALERT "mcp7d driver register failed.\n");
return retval;
}
if(show_debug)
printk( KERN_INFO "mcp7d driver register sccessed.\n");
struct spi_master *master;
struct spi_device *spi_device;
spi_register_driver(&spcd_driver);
spcd_info.bus_num = 0;
spcd_info.chip_select = 1;
master = spi_busnum_to_master(spcd_info.bus_num);
if( ! master ) {
printk( KERN_ERR "spi_busnum_to_master returned NULL\n");
spi_unregister_driver(&spcd_driver);
return -ENODEV;
}
spi_remove_device(master, spcd_info.chip_select);
spi_device = spi_new_device( master, &spcd_info );
if( !spi_device ) {
printk(KERN_ERR "spi_new_device returned NULL\n" );
spi_unregister_driver(&spcd_driver);
return -ENODEV;
}
return 0;
}
/**
* モジュールの終了処理
*/
static void spcd_exit(void)
{
int i;
dev_t devno;
if(show_debug) printk(KERN_INFO "[spcd_exit]\n");
if(show_debug) printk(KERN_INFO "[cdev_del]\n");
/* キャラクタデバイスの登録解除 */
for( i = 0; i < DRV_NUM_DEVS; i++ ) {
cdev_del(&(spcd.drv_cdev_array[i]));
devno = MKDEV(_spcd_major, _spcd_minor+i);
device_destroy(spcd.drv_class, devno);
}
/* メジャー番号/マイナー番号を取り除く */
devno = MKDEV(_spcd_major,_spcd_minor);
unregister_chrdev_region(devno, DRV_NUM_DEVS);
/* デバイスノードを取り除く */
class_destroy( spcd.drv_class );
kfree(spcd.drv_cdev_array);
if(show_debug) printk(KERN_INFO "[spcd_del]\n");
spi_unregister_driver(&spcd_driver);
}
module_init(spcd_init);
module_exit(spcd_exit);
module_param( show_debug, int, S_IRUSR | S_IRGRP | S_IROTH );
module_param( gpiono, int, S_IRUSR | S_IRGRP | S_IROTH );
//module_param( hexmode, int, S_IRUSR | S_IRGRP | S_IROTH );
view raw pic_clcd.c hosted with ❤ by GitHub

使いそびれたパラレルキャラクタ液晶のSPI化(1/2)

ずっと昔にまとめ買いした「LCDキャラクタディスプレイモジュール」(秋月電子のSC1602BSLB-XA-GB-KとかSD1602HULB-XA-G-G)が使いそびれていた。
5Vだしパラレル入力だし・・・。
最近では、3VとかI2C通信のものが安価に出ている。
困った。 FON2405E(Linuxボード)は 3Vだし、今のところSPIしか使えていない。
そこで、PICマイコン使って
  • インターフェース変換(SPI to パラレル)
  • 3V駆動
  • SW入力
  • バックライト
を目指す。

先に結論↓ こんな感じで、Linuxボードから制御してみた。



1. インターフェース変換

SPI搭載の手持ちPICマイコン=PIC16F818 / 819 にした。
まぁシフトレジスタでも実現できるような気がするけど。
http://www.aitendo.com/product/14623
だけど3V駆動化とかSW入力とかやりたいので、今回はPICにこだわった。


2. 3V駆動

いろいろな方が実現している。感謝!
PICにてPWM出力し、チャージポンプにて負電圧を生成する。
最初に思いついた方すごいね!
http://elm-chan.org/docs/lcd/lcd3v_j.html
http://jsdiy.web.fc2.com/lcd3v/


3. SW入力

入力ピンが足りないので、アナログ入力+抵抗分圧にて。
こちらもいろいろな方が実現している。感謝。
https://synapse.kyoto/hard/keypad/page001.html


4. バックライト

バックライト駆動するためには4V 40mA程度必要っぽい。
2のチャージポンプでは賄えないか・・・。
要検討・・・。

んでもって、現状の回路図はこんな感じ。


ソースコード
/*
* File: lcd_lib.c
* Author: adeno
*
* Created on 2018/06/25, 1:18
*/
#include <xc.h>
#include "lcd_lib.h"
/*
*
*/
void lcd_change_col(unsigned char i){
// if(i == 1) { lcd_cmd(0xC0); }
// else {lcd_cmd(0x80);}
if(i == 1){
lcd_out(0xC0,0);
lcd_out(0x00,0); //<<4
}else{
lcd_out(0x80,0);
lcd_out(0x00,0); //<<4
}
__delay_ms(2);
}
///
///LCDにコマンド・文字を出力
/// charflg=0 コマンド、charflg=1 文字
/// 要指定
/// #define lcd_e_bit
/// #define lcd_rs_bit
/// #define lcd_port PORTA この場合、RA3 - 0を使う
void lcd_out(unsigned char code,unsigned char charflg){
unsigned char port_bak;
unsigned char rs_bit = (1 << lcd_rs_bit);
unsigned char e_bit = (1 << lcd_e_bit);
//データ出力
port_bak = lcd_port & 0b11100001; //RA4 - 1
port_bak = port_bak | (0b00011110 & (code >> 3));
lcd_port = port_bak;
//rs set
port_bak = port_bak & (~rs_bit);
if (charflg == 1){
//RSをhigh
port_bak = port_bak | rs_bit;
}
lcd_port = port_bak;
//eにワンショット
port_bak = port_bak & (~e_bit);
lcd_port = port_bak | e_bit;
__nop();
lcd_port = port_bak;
}
void lcd_clear(){
lcd_cmd(0x01);
__delay_ms(15);
}
void lcd_init(){
//LCDの初期化
__delay_ms(15);
lcd_out(0x30,0);
__delay_ms(5);
lcd_out(0x30,0);
__delay_ms(1);
lcd_out(0x30,0);
__delay_ms(1);
lcd_out(0x20,0);
__delay_ms(1);
lcd_cmd(0x2e);
// lcd_out(0x2e,0);
// lcd_out(0xe0,0); //<<4
// __delay_ms(2);
lcd_cmd(0x08);
lcd_cmd(0x0d);
lcd_cmd(0x06);
lcd_cmd(0x02);
}
view raw lcd_lib.c hosted with ❤ by GitHub
/*
* File: lcd_lib.h
* Author: adeno
*
* Created on 2018/06/25, 1:20
*/
#ifndef LCD_LIB_H
#define LCD_LIB_H
#ifdef __cplusplus
extern "C" {
#endif
//出力にラッチがないPIC向けで、データと制御のポート群が同じ場合
//データ出力がRx4〜Rx1の場合
#define _XTAL_FREQ 8000000 //delay用に必要(クロック8MHzを指定)
//RA1 D4
//RA2 D5
//RA3 D6
//RA4 D7
//RA4 E
//RA6 RS
#define LCD_ROW 16
#define LCD_COL 2
#define lcd_port PORTA
#define lcd_e_bit 7
#define lcd_rs_bit 6
#define lcd_data(ascii) lcd_out(ascii,1);lcd_out(ascii << 4,1);__delay_us(50);
#define lcd_cmd(cmd) lcd_out(cmd,0);lcd_out(cmd << 4,0);__delay_ms(2);
void lcd_change_col(unsigned char i);
void lcd_out(unsigned char code,unsigned char charflg);
void lcd_init();
void lcd_clear();
#ifdef __cplusplus
}
#endif
#endif /* LCD_LIB_H */
view raw lcd_lib.h hosted with ❤ by GitHub
/*
* File: main.c
* Author: adeno
*
* Created on 2018/06/05, 3:25
*/
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
//#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "lcd_lib.h"
__EEPROM_DATA('S','p','i','C','h','a','r','L');
__EEPROM_DATA('C','D',' ','v','0','.','4',' ');
//PWM設定(16-)
__EEPROM_DATA(0b01,166, 83,0,1,0,0,0); //16 {0b01,166, 83,0,1}, //3kHz
__EEPROM_DATA(0b01,199,100,0,0,0,0,0); //24 {0b01,199,100,0,0}, //2.5kHz
__EEPROM_DATA(0b01,249,125,0,0,0,0,0); //32 {0b01,249,125,0,0}, //2kHz
__EEPROM_DATA(0b10, 82, 42,1,0,0,0,0); //40 {0b10, 82, 42,1,0}, //1.5kHz
__EEPROM_DATA(0b10,124, 62,1,0,0,0,0); //48 {0b10,124, 62,1,0}, //1kHz
__EEPROM_DATA(0b10,138, 69,0,1,0,0,0); //56 {0b10,138, 69,0,1}, //0.9kHz
__EEPROM_DATA(0b10,155, 78,0,0,0,0,0); //64 {0b10,155, 78,0,0}, //0.8kHz
void initPWM(void);
//void changePWMindex(unsigned char i);
//void changePWM(int ps,int pr,int duty,int d1y,int d1x);
void changePWMeepromindex(unsigned char i);
void initLCD(void);
void initAD(void);
void initSPI(void);
void initTMR0(void);
unsigned char getAD();
#define RBUFSIZE 32
#define RBUFMASK 0x1f
#define RCV_STATE_FUNC 0
#define RCV_STATE_CPWM 1
#define RCV_STATE_CCMD 2
#define RCV_STATE_CDATA 3
#define RCV_CMD_BKLIGHT 0x00
#define RCV_CMD_PWM 0x01
#define RCV_CMD_LCDCMD 0x02
#define RCV_CMD_LCDDATA 0x03
#define RCV_CMD_SW 0x04
#define RCV_CMD_LCDDATAFIN 0x00
#define RCV_DATA_PWM_0 16
#define RCV_DATA_PWM_1 24
#define RCV_DATA_PWM_2 32
#define RCV_DATA_PWM_3 40
#define RCV_DATA_PWM_4 48
#define RCV_DATA_PWM_5 56
#define RCV_DATA_PWM_6 64
#define GTIMER 131
unsigned char ringbuf[RBUFSIZE];
unsigned char wpoi = 0;
unsigned char rpoi = 0;
unsigned char rcvstate = 0;
unsigned char swadcflg = 0;
//struct pwmsetting {
// unsigned char ps;
// unsigned char pr;
// unsigned char duty;
// bool d1y;
// bool d1x;
//};
//struct pwmsetting pwmary[7] = {
// //ps, pr, duty, d1y, d1x
// {0b01,166, 83,0,1}, //3kHz
// {0b01,199,100,0,0}, //2.5kHz
// {0b01,249,125,0,0}, //2kHz
// {0b10, 82, 42,1,0}, //1.5kHz
// {0b10,124, 62,1,0}, //1kHz
// {0b10,138, 69,0,1}, //0.9kHz
// {0b10,155, 78,0,0}, //0.8kHz
// };
void putch(unsigned char c){
lcd_data(c);
return;
}
/*
*
*/
int main(/*int argc, char** argv*/) {
OSCCONbits.IRCF = 0b111; //8MHz
initPWM();
initAD();
initSPI();
initLCD();
initTMR0();
unsigned char adv;
// unsigned char i;
unsigned char oldsw = 0;
unsigned char sw = 0;
lcd_change_col(1);
TMR0 = GTIMER;
INTCONbits.TMR0IE = 1;
while(1){
if(swadcflg == 1){
swadcflg = 0;
adv = getAD();
if(adv > 21 && adv < 26){
//SW1
sw = 1;
}else if(adv > 54 && adv < 64){
//SW2
sw = 2;
}else if(adv > 105 && adv < 118){
//SW3
sw = 3;
}else if(adv > 157 && adv < 170){
//SW4
sw = 4;
}else if(adv > 210 && adv < 218){
//SW5
sw = 5;
}else if(adv > 238 && adv < 242){
//SW6
sw = 6;
}else{
sw = 0;
}
if(sw != oldsw){
lcd_data(sw+'0');
}
oldsw = sw;
}
// __delay_ms(1);
if(wpoi != rpoi){
if(rcvstate == RCV_STATE_FUNC){
if(ringbuf[rpoi] == RCV_CMD_PWM) { rcvstate = RCV_STATE_CPWM; }
else if(ringbuf[rpoi] == RCV_CMD_LCDDATA) { rcvstate = RCV_STATE_CDATA; }
else if(ringbuf[rpoi] == RCV_CMD_LCDCMD) { rcvstate = RCV_STATE_CCMD; }
}else if(rcvstate == RCV_STATE_CPWM){
sw = 0;
if(ringbuf[rpoi] == 0) { sw = RCV_DATA_PWM_0;}
else if(ringbuf[rpoi] == 1) { sw = RCV_DATA_PWM_1;}
else if(ringbuf[rpoi] == 2) { sw = RCV_DATA_PWM_2;}
else if(ringbuf[rpoi] == 3) { sw = RCV_DATA_PWM_3;}
else if(ringbuf[rpoi] == 4) { sw = RCV_DATA_PWM_4;}
else if(ringbuf[rpoi] == 5) { sw = RCV_DATA_PWM_5;}
else if(ringbuf[rpoi] == 6) { sw = RCV_DATA_PWM_6;}
changePWMeepromindex(sw);
rcvstate = RCV_STATE_FUNC;
}else if(rcvstate == RCV_STATE_CCMD){
lcd_cmd(ringbuf[rpoi]);
rcvstate = RCV_STATE_FUNC;
// if(ringbuf[rpoi] == RCV_CMD_LCDDATAFIN) { rcvstate = RCV_STATE_FUNC;}
// else{lcd_cmd(ringbuf[rpoi]);}
}else if(rcvstate == RCV_STATE_CDATA){
lcd_data(ringbuf[rpoi]);
rcvstate = RCV_STATE_FUNC;
// if(ringbuf[rpoi] == RCV_CMD_LCDDATAFIN) { rcvstate = RCV_STATE_FUNC;}
// else{lcd_data(ringbuf[rpoi]);}
}
rpoi = (rpoi+1) & RBUFMASK;
}
//
// __delay_ms(2000);
// changePWMindex(0);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 3kHz ");
//
// __delay_ms(2000);
// changePWMindex(1);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 2.5kHz ");
//
// for(i=0;i<100;i++){
// __delay_ms(200);
// adv = getAD();
// lcd_change_col(1);
// printf("AD> %d ",adv);
// }
//
// __delay_ms(2000);
// changePWMindex(2);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 2kHz ");
//
// __delay_ms(2000);
// changePWMindex(3);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 1.5kHz ");
//
//// __delay_ms(2000);
//// changePWMindex(4);
//// lcd_change_col(1);
//// // 0123456789ABCDEF
//// printf("PWM> 1kHz ");
////
//// __delay_ms(2000);
//// changePWMindex(5);
//// lcd_change_col(1);
//// // 0123456789ABCDEF
//// printf("PWM> 0.9kHz ");
////
//// __delay_ms(2000);
//// changePWMindex(6);
//// lcd_change_col(1);
//// // 0123456789ABCDEF
//// printf("PWM> 0.8kHz ");
}
return (EXIT_SUCCESS);
}
void initLCD(void){
//RA1 D4
//RA2 D5
//RA3 D6
//RA4 D7
//RA6 RS
//RA7 E
TRISAbits.TRISA1 = 0;
TRISAbits.TRISA2 = 0;
TRISAbits.TRISA3 = 0;
TRISAbits.TRISA4 = 0;
TRISAbits.TRISA6 = 0;
TRISAbits.TRISA7 = 0;
ADCON1 = 0b1110; //4-1:D 0:A
__delay_ms(100);
//LCDの初期化
lcd_init();
//LCDの表示クリア
lcd_clear();
// dist = DIST_LCD;
// 0123456789ABCDEF
// printf("SpiCharLCD v0.1a");
// lcd_change_col(1);
// printf(">");
// lcd_cmd(0xc0);
unsigned char i,d;
for(i=0;i<16;i++){
d = eeprom_read(i);
lcd_data(d);
}
// lcd_data('S'); lcd_data('p'); lcd_data('i');
// lcd_data('C'); lcd_data('h'); lcd_data('a'); lcd_data('r');
// lcd_data('L'); lcd_data('C'); lcd_data('D'); lcd_data(' ');
// lcd_data('v'); lcd_data('0'); lcd_data('.'); lcd_data('1'); lcd_data('b');
}
void initPWM(void){
//PWM
//1)Set the PWM period by writing to the PR2 register.
//周期 = ( PR2 + 1 ) x 4 x 1クロック分の時間 x プリスケーラ値
//10kHz 周期0.1ms = (PR2+1)x4x(1/8MHz)xPrescale
// 10^-4 = S*4*(1/8)*10^-6*P
// 2*10^2 = S*P
// 200 = (PR2+1)*P --- P=1 PR2=199
CCP1CON = 0b00001100; //PWMを使用
// T2CONbits.T2CKPS = 0b00; //プリスケーラ値1
// PR2 = 199;
//2)Set the PWM duty cycle by writing to the
//CCPR1L register and CCP1CON<5:4> bits.
//PWM Duty Cycle = (CCPR1L:CCP1CON<5:4>) •TOSC • (TMR2 Prescale Value)
//50% 0.1ms*50% 0.05ms=50us
//PWM Duty Cycle = V * (1/8MHz) * 1
//DC = V * 1/8 * 10^-6
//50*10^-6 = V*1/8*10^-6
//400 = V
//Vの下位2bitはCCP1x-CCP1Y
//vの上位8bitはCCPR1L
// CCPR1L = 100;
// CCP1CONbits.CCP1Y = 0;
// CCP1CONbits.CCP1X = 0;
//3)Make the CCP1 pin an output by clearing the TRISB<x> bit.
TRISBbits.TRISB3 = 0;
//4)Set the TMR2 prescale value and enable Timer2 by writing to T2CON.
// T2CONbits.TMR2ON = 1;
//50%
//プリスケーラ PR2 CCPR1L CCP1Y CCP1X
//10kHz 1 00 199 100 0 0
//5kHz 4 01 99 50 0 0
//1kHz 16 1x 124 62.5 1 0
// changePWMindex(3);
changePWMeepromindex(40);
}
//void changePWMindex(unsigned char i){
// T2CONbits.TMR2ON = 0;
// T2CONbits.T2CKPS = pwmary[i].ps; //プリスケーラ値1
// PR2 = pwmary[i].pr;
// CCPR1L = pwmary[i].duty;
//
// CCP1CONbits.CCP1Y = pwmary[i].d1y;
// CCP1CONbits.CCP1X = pwmary[i].d1x;
// T2CONbits.TMR2ON = 1;
//}
void changePWMeepromindex(unsigned char i){
T2CONbits.TMR2ON = 0;
T2CONbits.T2CKPS = eeprom_read(i); //プリスケーラ値1
PR2 = eeprom_read(i+1);
CCPR1L = eeprom_read(i+2);
CCP1CONbits.CCP1Y = eeprom_read(i+3);
CCP1CONbits.CCP1X = eeprom_read(i+4);
T2CONbits.TMR2ON = 1;
}
//void changePWM(int ps,int pr,int duty,int d1y,int d1x){
// T2CONbits.TMR2ON = 0;
// T2CONbits.T2CKPS = (unsigned int)ps; //プリスケーラ値1
// PR2 = (unsigned int)pr;
// CCPR1L = (unsigned int)duty;
// CCP1CONbits.CCP1Y = (unsigned int)d1y;
// CCP1CONbits.CCP1X = (unsigned int)d1x;
// T2CONbits.TMR2ON = 1;
//}
void initAD(){
ADCON1 = 0b1110; //4-1:D 0:A
//16TOSC 1 01 10MHz
ADCON1bits.ADCS2 = 1;
ADCON1bits.ADFM = 0; //左づめ
// ADCON0bits.ADCS = 0b01;
// ADCON0bits.CHS = 0b000;
// ADCON0bits.ADON = 1;
ADCON0 = 0b01000001;
}
unsigned char getAD(){
ADCON0bits.GO = 1;
__delay_us(20);
while(ADCON0bits.GO){
}
return ADRESH;
}
void initSPI(){
SSPCONbits.SSPM = 0b0100;
SSPCONbits.SSPEN = 1;
TRISBbits.TRISB1 = 1; //SDI
TRISBbits.TRISB2 = 0; //SDO
TRISBbits.TRISB4 = 1; //SCK
TRISBbits.TRISB5 = 1; //SS
//mode SSPCON(CKP) SSPSTAT(CKE)
//1 0,1 0 0
//3 1,1 1 0
//0 0,0 0,1
//2 1,0 1,1
SSPCONbits.CKP = 1;
SSPSTATbits.CKE = 0;
PIE1bits.SSPIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
}
void interrupt ISR(void)
{
if(PIR1bits.SSPIF == 1){
PIR1bits.SSPIF = 0;
ringbuf[wpoi] = SSPBUF;
wpoi = (wpoi+1) & RBUFMASK;
// TMR0 = GTIMER;
// INTCONbits.TMR0IE = 1;
}else if(INTCONbits.TMR0IF == 1){
//rcvstate = 10;
swadcflg = 1;
TMR0 = GTIMER;
INTCONbits.TMR0IF = 0;
}
//lcd_data(SSPBUF);
}
void initTMR0(void){
OPTION_REGbits.PS = 0b011;
OPTION_REGbits.PSA = 0;
OPTION_REGbits.T0CS = 0;
}
view raw main.c hosted with ❤ by GitHub