https://blog.naver.com/chldmstjd07/222953613192
Humidity & Temperature Sensor DHT11(aosong) => LCD display
DHT11 1. 전압 : DC 3.3 ~ 5.5V 2. 센서에 전원이 공급되면 1초 동안은 명령어 전달 금지. 3. 센서는...
blog.naver.com
/*
* FinalTest.c
*
* Created: 2022-12-12 오후 4:43:01
* Author : Owner
*/
#define MHZ_F_CPU 5
#define F_CPU MHZ_F_CPU*1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "spi.h"
#define RCIV0_MIN MHZ_F_CPU * 11
#define RCIV0_MAX MHZ_F_CPU * 16
#define RCIV1_MIN MHZ_F_CPU * 33
#define RCIV1_MAX MHZ_F_CPU * 37
#define COMME_MIN MHZ_F_CPU * 39
#define COMME_MAX MHZ_F_CPU * 41
//segment
#define SEG_DIGIT (PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm)
typedef enum { BLINK_FAST, BLINK_NORMAL, BLINK_SLOW } blink_rate_t;
struct digitinfo {
uint8_t segmentBuffer;
bool dot;
bool blink;
blink_rate_t blink_rate;
};
struct digitinfo digitInfo[4] = {
{ 0xff, false, false, BLINK_FAST },
{ 0xff, false, false, BLINK_FAST },
{ 0xff, false, false, BLINK_FAST },
{ 0xff, false, false, BLINK_FAST }
};
// 0 1 2 3 4 5 6 7 8 9 a b c d e f -
const uint8_t segPattern[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x27, 0x7f, 0x67, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x40 };
void displayUnsignedDecimal( uint16_t dat, bool zk );
void SegmentOutIsr( uint16_t idx );
void BlinkAll( void );
void BlinkClear(void);
//DHT11
#define DHT11_DATA_EERRCODE 125
struct DHT11info {
uint8_t data[5];
uint8_t BitCounter;
bool DisplayFlag;
bool NonErrorFlag;
bool DataErrorFlag;
};
struct DHT11info DHT11 = {
{0,0,0,0,0},
0, false, false, false
};
void Channeling_And_TCB2Ini_WithoutEnable (void);
void DHT11_StateControl_TCB0_ISR (void);
void DHT11_State_Start (void);
void DHT11_State_StartReadData (void);
void DHT11_State_StandbyMode (void);
void DHT11_State_Check_ReceiptData (void);
void DHT11_ReadData_TCB2_ISR (void);
void DHT11_Display_main (void);
ISR( TCB0_INT_vect ) {
static uint16_t Cnt_1ms = 0;
uint16_t CntHz5;
Cnt_1ms++;
CntHz5 = Cnt_1ms % 5;
if ( CntHz5 == 1 ) SegmentOutIsr( Cnt_1ms );
if ( CntHz5 == 3 ) SendLCDbySpiISR();
DHT11_StateControl_TCB0_ISR();
TCB0.INTFLAGS |= TCB_CAPT_bm;
}
ISR( TCB2_INT_vect ) {
cli(); // TCB0 Interrupt Preventing
DHT11_ReadData_TCB2_ISR();
TCB2.INTFLAGS |= TCB_CAPT_bm;
sei();
}
int main(void)
{
// Main clock 10MHz or 5MHz
if(MHZ_F_CPU == 10){
CCP = CCP_IOREG_gc;
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm;
}
else{
CCP = CCP_IOREG_gc;
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm;
}
// 7-segment FND port initial
PORTC.DIR = 0xff;
PORTF.DIRSET = SEG_DIGIT;
Channeling_And_TCB2Ini_WithoutEnable();
InitializeSPI();
_delay_ms(2000);
DHT11_State_StandbyMode();
sei();
InitializeIOX();
// TCB0 Initialization for 1000 Hz periodic interrupt
TCB0.CCMP = 5000;
TCB0.CTRLA |= TCB_ENABLE_bm;
TCB0.INTCTRL |= TCB_CAPT_bm;
if(MHZ_F_CPU == 10) TCB0.CTRLA |= TCB_CLKSEL_CLKDIV2_gc;
InitializeIOX_CLCD();
IOX_CLCD_DisplayString( 0, 0, "Hello ATMEGA4809");
_delay_ms(1000);
IOX_CLCD_ClearDisplay();
digitInfo[1].dot = true;
while (1)
{
DHT11_Display_main();
}
}
////////////////////////////////////////////////////////////////////////////////////////
void Channeling_And_TCB2Ini_WithoutEnable(void){
// TCB2 initialize without enable
TCB2.CTRLB |= TCB_CNTMODE_PW_gc;
TCB2.EVCTRL |= TCB_CAPTEI_bm;
TCB2.CTRLA |= TCB_CLKSEL_CLKDIV2_gc;
TCB2.INTCTRL |= TCB_CAPT_bm;
// ECHO -> PD0 -> CHANNEL3 -> TCB2
EVSYS.CHANNEL3 |= EVSYS_GENERATOR_PORT1_PIN0_gc;
EVSYS.USERTCB2 |= EVSYS_CHANNEL_CHANNEL3_gc;
}
void DHT11_StateControl_TCB0_ISR(void){
static uint16_t cnt = 0;
cnt++;
switch(cnt){
case 1: DHT11_State_Start(); break;
case 19: DHT11_State_StartReadData(); break;
case 25: DHT11_State_Check_ReceiptData(); break;
case 26: DHT11_State_StandbyMode(); break;
case 2000: cnt = 0; break;
default: break;
}
}
void DHT11_State_Start(void){
DHT11.BitCounter = 0;
DHT11.data[3] = DHT11.data[2] = DHT11.data[0] = DHT11.data[1] = DHT11.data[4] = 0;
PORTD.OUTCLR = PIN0_bm;
}
void DHT11_State_StartReadData(void) {
//input mode & high
PORTD.OUTSET = PIN0_bm;
_delay_us(40);
PORTD.DIRCLR = PIN0_bm;
//TCB2 enable
TCB2.CTRLA |= TCB_ENABLE_bm;
}
void DHT11_State_Check_ReceiptData(void){
if(DHT11.data[3] + DHT11.data[2] + DHT11.data[0] + DHT11.data[1] == DHT11.data[4])
DHT11.NonErrorFlag = true;
else
DHT11.DataErrorFlag = true;
}
void DHT11_State_StandbyMode(void) {
//TCB2 disable
TCB2.CTRLA &= ~TCB_ENABLE_bm;
//output mode & high
PORTD.DIRSET = PIN0_bm;
PORTD.OUTSET = PIN0_bm;
DHT11.DisplayFlag = true;
}
void DHT11_ReadData_TCB2_ISR(void){
//All protocols must be completed in at least 76us
//0
if(RCIV0_MIN <TCB2.CCMP && TCB2.CCMP < RCIV0_MAX){
DHT11.BitCounter++;
}
// 1
else if(RCIV1_MIN <TCB2.CCMP && TCB2.CCMP < RCIV1_MAX){
DHT11.BitCounter++;
switch(DHT11.BitCounter)
{
case 1 ... 8 :
DHT11.data[0] |= 128 >> (DHT11.BitCounter - 1); break;
case 9 ... 16 :
DHT11.data[1] |= 128 >> (DHT11.BitCounter - 9); break;
case 17 ... 24 :
DHT11.data[2] |= 128 >> (DHT11.BitCounter - 17); break;
case 25 ... 32 :
DHT11.data[3] |= 128 >> (DHT11.BitCounter - 25); break;
case 33 ... 40 :
DHT11.data[4] |= 128 >> (DHT11.BitCounter - 33); break;
default : break;
}
}
}
void DHT11_Display_main(void){
char tBuffer[16] = { 0 };
char hBuffer[16] = { 0 };
if(DHT11.DisplayFlag){
cli(); DHT11.DisplayFlag = false; sei();
if(DHT11.NonErrorFlag ){
cli(); DHT11.NonErrorFlag = false; sei();
BlinkClear();
displayUnsignedDecimal( (DHT11.data[2] + DHT11.data[0] * 100) , true );
//
sprintf(hBuffer, "Humidity : %5d", DHT11.data[0]);
IOX_CLCD_DisplayString( 0, 0, hBuffer);
_delay_ms(10);
sprintf(tBuffer, "Temperature : %2d", DHT11.data[2]);
IOX_CLCD_DisplayString( 1, 0, tBuffer);
//
}
if(DHT11.DataErrorFlag ){
cli(); DHT11.DataErrorFlag = false; sei();
BlinkAll();
displayUnsignedDecimal( DHT11_DATA_EERRCODE , true );
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
void SegmentOutIsr( uint16_t idx ) {
uint8_t didx;
didx = (uint8_t)(idx & 0x03);
if ( digitInfo[didx].blink && (idx & (1 << ((uint16_t)digitInfo[didx].blink_rate*2 + 7))) ) {
PORTF.OUTCLR = SEG_DIGIT;
} else {
PORTF.OUTCLR = SEG_DIGIT; // DIGIT all clear
PORTC.OUT = (digitInfo[didx].dot)? (digitInfo[didx].segmentBuffer | 0x80) : digitInfo[didx].segmentBuffer;
PORTF.OUTSET = 1 << didx;
}
}
void BlinkClear( void ) {
digitInfo[0].blink = digitInfo[1].blink = digitInfo[2].blink = digitInfo[3].blink = false;
}
void BlinkAll( void ) {
digitInfo[0].blink = digitInfo[1].blink = digitInfo[2].blink = digitInfo[3].blink = true;
}
void displayUnsignedDecimal( uint16_t dat, bool zk ) {
uint8_t tmpBuffer[4];
if ( dat > 9999 ) {
dat = 9999; BlinkAll();
for ( int8_t i = 0 ; i < 4 ; i++ )
digitInfo[i].segmentBuffer = segPattern[16];
} else {
tmpBuffer[0] = segPattern[dat / 1000];
tmpBuffer[1] = segPattern[(dat % 1000) / 100];
tmpBuffer[2] = segPattern[(dat % 100) / 10];
tmpBuffer[3] = segPattern[dat % 10];
if ( zk ) {
if ( tmpBuffer[0] == 0x3f) tmpBuffer[0] = 0;
if ( tmpBuffer[2] == 0x3f) tmpBuffer[2] = 0;
}
for ( int8_t i = 0 ; i < 4 ; i++ )
digitInfo[i].segmentBuffer = tmpBuffer[i];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
spi.h
/*
* spi.h
*
* Created: 2022-10-18 오후 2:27:45
* Author: Tae Min Shin
*/
#ifndef SPI_H_
#define SPI_H_
#define E_On ( 0b00001000 )
#define E_Off ( 0b11110111 )
#define RS_On ( 0b00000010 )
#define RS_Off ( 0b11111101 )
#define RW_On ( 0b00000100 )
#define RW_Off ( 0b11111011 )
//
#define SS_HIGH ( PORTA.OUTSET = PIN7_bm )
#define SS_LOW ( PORTA.OUTCLR = PIN7_bm )
typedef enum {
SPI_FREE,
SPI_IDLE,
SPI_BUSY,
SPI_DONE
} SPI_XferStaus_t;
typedef enum {
spi_readwrite,
spi_repeatBlock,
spi_readstop,
spi_stop
} spi_operation_t;
typedef spi_operation_t (*spi_callback_t)( void * p );
typedef struct spi_desciption {
uint8_t *pBlockData;
uint8_t Size;
volatile SPI_XferStaus_t Status;
volatile uint8_t blockNo;
spi_callback_t callbackDataXferComplete;
void * callbackParameter;
} SPI_DESC_t;
// MCP23S17 IO EXPANDER REGISTERS
#define IOX_ADR_WRITE 0x40
#define IOX_ADR_READ 0x41
#define IOX_IODIRA 0x00
#define IOX_IODIRB 0x01
#define IOX_IOCON 0x0a
#define IOX_GPIOA 0x12
#define IOX_GPIOB 0x13
void InitializeSPI( void );
void InitializeIOX( void );
void SPI_Block_ReadWriteStart( uint8_t *block, uint8_t size );
void ScanKeySwISR( void );
void SendLCDbySpiISR( void );
void InitializeIOX_CLCD( void );
void IOX_CLCD_ClearDisplay( void );
void IOX_CLCD_GotoRC( uint8_t row, uint8_t col );
void IOX_CLCD_DisplayString( uint8_t r, uint8_t c, char *str );
void IOX_CLCD_makeFont( uint8_t addr, uint8_t *user_font );
void IOX_CLCD_DisplayChar( uint8_t chr );
void IOX_CLCD_DisplayBar( uint8_t r, uint8_t c, uint8_t bar );
#endif /* SPI_H_ */
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
spi.c
/*
* spi.c
*
* Created: 2022-10-18 오후 2:27:20
* Created: 2021-11-08 오후 5:36:58
* Author: Tae Min Shin
*/
#define F_CPU 5000000UL // Max System Clock Frequency at 1.8V ~ 5.5V VDD
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdio.h>
#include "spi.h"
#define PIG
void IOX_Send2LCD_Async( uint8_t dat, bool rs );
void IOX_CLCD_regFontData( void );
extern struct {
bool FP, CP;
uint8_t DIE, SUR;
uint8_t TR1, TR2;
bool ROL, HOLD, NEW_GAME; // Input SW
bool WIN;
} PigData;
extern enum pigmode { PigNONE, Pig1Player, Pig2Player } Pig;
extern volatile uint8_t gkswScanCode;
extern volatile bool gkswFlag;
static const uint8_t UserFont[8][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0
{ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // 1
{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }, // 2
{ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c }, // 3
{ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e }, // 4
{ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }, // 5
{ 0 }, // 6
{ 0 } // 7
};
uint8_t KeySwCol;
SPI_DESC_t SPI_Desc = { 0 };
uint8_t spi_buff[32];
void InitializeSPI( void ) {
SPI_Desc.Status = SPI_FREE;
PORTA.DIRSET = PIN4_bm | PIN6_bm | PIN7_bm; //PA4(MO), PA5(MI):INPUT, PA6(SCK), PA7(SS)
PORTA.OUTSET = PIN7_bm; // SS : Normal High
SPI0.CTRLA = SPI_MASTER_bm | SPI_ENABLE_bm; // Master Mode, 5/4MHz, SPI Enable, Mode 0
SPI0.INTCTRL = SPI_IE_bm;
SPI_Desc.Status = SPI_IDLE;
}
spi_operation_t SPI_Stop_CB( void * p ) {
return spi_stop;
}
void SPI_SetDataXferCompleteCallBack( spi_callback_t cb, void * p ) {
if ( cb ) {
SPI_Desc.callbackDataXferComplete = cb;
SPI_Desc.callbackParameter = p;
} else {
SPI_Desc.callbackDataXferComplete = SPI_Stop_CB;
SPI_Desc.callbackParameter = NULL;
}
}
spi_operation_t SPI_InitIOX_CB( void *p ) {
SPI_Desc.pBlockData = p;
SPI_Desc.Size = 3;
SPI_SetDataXferCompleteCallBack( SPI_Stop_CB, NULL );
return spi_readwrite;
}
void InitializeIOX( void ) {
SPI_Desc.Status = SPI_IDLE;
spi_buff[0] = IOX_ADR_WRITE; // Slave Address/Wr
spi_buff[1] = IOX_IOCON; // IOCON
spi_buff[2] = 0x30; // SEQOP Disable, DISSLW Disable
spi_buff[3] = IOX_ADR_WRITE; // Slave Address/Wr
spi_buff[4] = IOX_IODIRB; // IODIR B
spi_buff[5] = 0x0f; // GPB0-3 : Input, GPB4-7 : Output
SPI_SetDataXferCompleteCallBack( SPI_InitIOX_CB, &spi_buff[3] );
SPI_Block_ReadWriteStart( spi_buff, 3 );
while ( SPI_Desc.Status == SPI_BUSY ) ;
_delay_ms(1);
SPI_Desc.Status = SPI_IDLE;
spi_buff[0] = IOX_ADR_WRITE; // Slave Address/Wr
spi_buff[1] = IOX_IODIRA; // IODIR A
spi_buff[2] = 0x01; // GPA0 : Input(1), GPA1-7 : Output(0)
spi_buff[3] = IOX_ADR_WRITE; // Slave Address/Wr
spi_buff[4] = IOX_GPIOA; // GPIOA
spi_buff[5] = 0x00; // 00
SPI_SetDataXferCompleteCallBack( SPI_InitIOX_CB, &spi_buff[3] );
SPI_Block_ReadWriteStart( spi_buff, 3 );
while ( SPI_Desc.Status == SPI_BUSY ) ;
}
spi_operation_t SPI_ReadStop_CB( void * p ) {
return spi_readstop;
}
ISR( SPI0_INT_vect ) {
SPI0.INTFLAGS |= SPI_IF_bm;
*SPI_Desc.pBlockData++ = SPI0.DATA;
if ( --SPI_Desc.Size > 0 ) {
SPI0.DATA = *SPI_Desc.pBlockData;
} else {
SS_HIGH;
switch ( SPI_Desc.callbackDataXferComplete(SPI_Desc.callbackParameter)) {
case spi_repeatBlock :
case spi_readwrite :
SS_LOW;
SPI0.DATA = *SPI_Desc.pBlockData;
break;
case spi_readstop :
KeySwCol = SPI0.DATA;
case spi_stop :
SPI_Desc.Status = SPI_DONE;
break;
}
}
}
void SPI_Block_ReadWriteStart( uint8_t *block, uint8_t size ) {
SPI_Desc.pBlockData = block;
SPI_Desc.Size = size;
SPI_Desc.Status = SPI_BUSY;
SS_LOW;
SPI0.DATA = *block;
}
spi_operation_t SPI_getKeySW_CB( void *p ) {
SPI_Desc.pBlockData = p;
SPI_Desc.Size = 3;
SPI_SetDataXferCompleteCallBack( SPI_ReadStop_CB, NULL );
return spi_readwrite;
}
void getKeySW( uint8_t row ) {
SPI_Desc.Status = SPI_IDLE;
spi_buff[0] = IOX_ADR_WRITE; // Slave Address/Wr
spi_buff[1] = IOX_GPIOB; // GPIOB B Out
spi_buff[2] = row; // Out Data to High Nibble
spi_buff[3] = IOX_ADR_READ; // Slave Address/Wr
spi_buff[4] = IOX_GPIOB; // GPIOB B In form Low Nibble
spi_buff[5] = 0x00; // In Data
SPI_SetDataXferCompleteCallBack( SPI_getKeySW_CB, &spi_buff[3] );
SPI_Block_ReadWriteStart( spi_buff, 3 );
}
typedef enum { kswILDE0, kswILDE1, kswPRESSING, kswScanRow0, kswScanRow1, kswScanRow2, kswScanRow3, kswPRESSED, kswRELEASING } KeySW_State_t;
void ScanKeySwISR( void ) { // in ISR
static KeySW_State_t SwitchState = kswILDE0;
uint8_t i, col;
switch ( SwitchState ) {
case kswILDE0 :
getKeySW(0x00); SwitchState = kswILDE1;
#ifdef PIG
PigData.ROL = PigData.HOLD = PigData.NEW_GAME = false;
#endif
break;
case kswILDE1 :
if ( (KeySwCol & 0xf) != 0xf ) SwitchState = kswPRESSING;
getKeySW(0x00);
break;
case kswPRESSING :
if ( (KeySwCol & 0xf) != 0xf ) {
SwitchState = kswScanRow0;
getKeySW(~PIN4_bm);
} else {
SwitchState = kswILDE1;
getKeySW(0x00);
}
break;
case kswScanRow0 :
col = KeySwCol & 0xf;
if ( col == 0xf ) {
SwitchState = kswScanRow1;
getKeySW(~PIN5_bm);
} else {
for ( i = 0 ; i < 4 ; i++ ) {
if ( (col & ( 1 << i )) == 0 ) {
gkswScanCode = i; gkswFlag = true;
SwitchState = kswPRESSED;
getKeySW(0x00);
break;
}
}
}
break;
case kswScanRow1 :
col = KeySwCol & 0xf;
if ( col == 0xf ) {
SwitchState = kswScanRow2;
getKeySW(~PIN6_bm);
} else {
for ( i = 0 ; i < 4 ; i++ ) {
if ( (col & ( 1 << i )) == 0 ) {
gkswScanCode = i + 4; gkswFlag = true;
SwitchState = kswPRESSED;
getKeySW(0x00);
break;
}
}
}
break;
case kswScanRow2 :
col = KeySwCol & 0xf;
if ( col == 0xf ) {
SwitchState = kswScanRow3;
getKeySW((uint8_t)~PIN7_bm);
} else {
for ( i = 0 ; i < 4 ; i++ ) {
if ( (col & ( 1 << i )) == 0 ) {
gkswScanCode = i + 8; gkswFlag = true;
SwitchState = kswPRESSED;
getKeySW(0x00);
break;
}
}
}
break;
case kswScanRow3 :
col = KeySwCol & 0xf;
if ( col != 0xf ) {
for ( i = 0 ; i < 4 ; i++ ) {
if ( (col & ( 1 << i )) == 0 ) {
gkswScanCode = i + 12; gkswFlag = true;
break;
}
}
} else {
gkswScanCode = 0xff; gkswFlag = true;
}
#ifdef PIG
if ( gkswScanCode == 12 ) PigData.NEW_GAME = true; // '*'
if ( gkswScanCode == 13 ) PigData.ROL = true; // '0'
if ( gkswScanCode == 14 ) PigData.HOLD = true; // '#'
#endif
SwitchState = kswPRESSED;
getKeySW(0x00);
break;
case kswPRESSED :
if ( (KeySwCol & 0xf) == 0xf ) SwitchState = kswRELEASING;
getKeySW(0x00);
break;
case kswRELEASING :
if ( (KeySwCol & 0xf) != 0xf ) SwitchState = kswPRESSED;
else {
SwitchState = kswILDE1;
#ifdef PIG
PigData.ROL = PigData.HOLD = PigData.NEW_GAME = false;
#endif
}
getKeySW(0x00);
break;
default:
SwitchState = kswILDE0;
break;
}
}
//
//
typedef enum { op_idle, op_ready, op_busy, op_done } clcd_op_t;
struct clcd_buff {
unsigned char Buffer[32];
volatile unsigned char Size;
volatile unsigned char Count;
volatile bool RS;
volatile clcd_op_t Status;
} ClcdData;
typedef enum { Clcd_WaitData, Clcd_SendSpi } clcd_state_t;
void SendLCDbySpiISR( void ) {
static clcd_state_t clcd_state = Clcd_WaitData;
switch( clcd_state ) {
case Clcd_WaitData :
if ( ClcdData.Status == op_ready ) {
ClcdData.Count = 0;
ClcdData.Status = op_busy;
clcd_state = Clcd_SendSpi;
}
break;
case Clcd_SendSpi :
if ( ClcdData.Size-- > 0 )
IOX_Send2LCD_Async( ClcdData.Buffer[ClcdData.Count++], ClcdData.RS );
else {
ClcdData.Status = op_done;
clcd_state = Clcd_WaitData;
}
break;
default:
clcd_state = Clcd_WaitData;
break;
}
}
spi_operation_t SPI_Send2LCD_CB( void *p ) {
SPI_Desc.Size = 3;
if ( --SPI_Desc.blockNo == 0 )
SPI_SetDataXferCompleteCallBack( SPI_Stop_CB, NULL );
return spi_repeatBlock;
}
void IOX_Send2LCD_Async( uint8_t dat, bool rs ) { // RS true : data, RS false : inst
uint8_t *pBuff;
uint8_t ctl;
SPI_Desc.Status = SPI_IDLE;
pBuff = spi_buff;
*pBuff++ = IOX_ADR_WRITE; // Slave Address/Wr
*pBuff++ = IOX_GPIOA; // GPIOA Out
*pBuff++ = ctl = (rs)? ((dat & 0xf0) | RS_On) : (dat & 0xf0); // Out Data to High Nibble
*pBuff++ = IOX_ADR_WRITE;
*pBuff++ = IOX_GPIOA;
*pBuff++ = ctl + E_On; //
*pBuff++ = IOX_ADR_WRITE;
*pBuff++ = IOX_GPIOA;
*pBuff++ = ctl & E_Off; //
*pBuff++ = IOX_ADR_WRITE;
*pBuff++ = IOX_GPIOA;
*pBuff++ = ctl = (rs)? ((dat << 4) | RS_On) : (dat << 4); //
*pBuff++ = IOX_ADR_WRITE;
*pBuff++ = IOX_GPIOA;
*pBuff++ = ctl + E_On; //
*pBuff++ = IOX_ADR_WRITE;
*pBuff++ = IOX_GPIOA;
*pBuff++ = ctl & E_Off; //
SPI_Desc.blockNo = 5;
SPI_SetDataXferCompleteCallBack( SPI_Send2LCD_CB, &spi_buff[3] );
SPI_Block_ReadWriteStart( spi_buff, 3 );
}
void IOX_CLCD_SendInst( uint8_t dat ) {
ClcdData.Buffer[0] = dat;
ClcdData.Size = 1;
ClcdData.RS = false;
ClcdData.Status = op_ready;
while ( ClcdData.Status != op_done ) ;
}
void IOX_CLCD_SendData( uint8_t dat ) {
ClcdData.Buffer[0] = dat;
ClcdData.Size = 1;
ClcdData.RS = true;
ClcdData.Status = op_ready;
while ( ClcdData.Status != op_done ) ;
}
void InitializeIOX_CLCD( void ) {
_delay_ms(30);
IOX_CLCD_SendInst(0x20);
_delay_us(50);
IOX_CLCD_SendInst(0x20);
_delay_us(50);
IOX_CLCD_SendInst(0x28);
_delay_us(50);
IOX_CLCD_SendInst(0x0c);
_delay_us(50);
IOX_CLCD_SendInst(0x01);
_delay_ms(2);
IOX_CLCD_SendInst(0x06);
_delay_us(50);
ClcdData.Status = op_idle;
IOX_CLCD_regFontData();
}
void IOX_CLCD_ClearDisplay( void ) {
IOX_CLCD_SendInst( 0x01 );
_delay_ms(2);
}
void IOX_CLCD_GotoRC( uint8_t row, uint8_t col )
{
col %= 16; //열 16칸, 0-14
row %= 2; //행 2칸, 0-1
uint8_t address = (0x40 * row) + col; //0행: 0x00, 1행: 0x40부터 주소 시작
IOX_CLCD_SendInst( 0x80 + address );
}
void IOX_CLCD_DisplayString( uint8_t r, uint8_t c, char *str ) {
uint8_t i, t;
IOX_CLCD_GotoRC( r, c );
for ( i = 0 ; ; i++ ) {
if ( (t = *str++) ) {
ClcdData.Buffer[i] = (unsigned char)t;
} else break;
}
ClcdData.Size = i;
ClcdData.RS = true;
ClcdData.Status = op_ready;
while ( ClcdData.Status != op_done ) ;
}
///
void IOX_CLCD_DisplayChar( uint8_t chr ) {
ClcdData.Buffer[0] = chr;
ClcdData.Size = 1;
ClcdData.RS = true;
ClcdData.Status = op_ready;
while ( ClcdData.Status != op_done ) ;
}
///
void IOX_CLCD_makeFont( uint8_t addr, uint8_t *user_font )
{
IOX_CLCD_SendInst( 0x40 + addr * 8 );
for( uint8_t i = 0; i < 8; i++ ) {
IOX_CLCD_SendData( user_font[i] );
}
}
///
void IOX_CLCD_regFontData( void ) {
for ( uint8_t i = 0 ; i < 8 ; i++ ) {
IOX_CLCD_makeFont(i, UserFont[i]);
}
}
///
void IOX_CLCD_DisplayBar( uint8_t r, uint8_t c, uint8_t bar ) {
uint8_t bar5, bar0;
static uint8_t lastBar5 = 0;
bar5 = bar / 5; bar0 = bar % 5;
if (lastBar5 > bar5)
{
IOX_CLCD_GotoRC(r, c + bar5);
IOX_CLCD_DisplayChar(bar0);
for ( uint8_t i = 0 ; i < lastBar5 - bar5 ; i++ )
IOX_CLCD_DisplayChar('\000');
}
else
{
IOX_CLCD_GotoRC(r, c + lastBar5);
for ( uint8_t i = 0 ; i < bar5 - lastBar5 ; i++ )
IOX_CLCD_DisplayChar('\005');
IOX_CLCD_DisplayChar(bar0);
}
lastBar5 = bar5;
}
'2022 하반기 > Atmel AVR(MCU)' 카테고리의 다른 글
SPI (Atmega4809) Keypad & I/O expander (0) | 2023.01.04 |
---|---|
Atmega4809 UART (0) | 2023.01.04 |
댓글