본문 바로가기
2022 하반기/Atmel AVR(MCU)

(Atmega4809)Humidity & Temperature Sensor DHT11(aosong) => LCD display

by concho 2023. 1. 4.

 

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

댓글