사용한 MAX7219 7-sement 모듈

  • 통신 방법 : SPI (최대속도 : 10Mhz)
  • 작동 전압 : 4.0~5.5
  • 환경 : P-NUCLEO-WB55 개발 보드, Atollic TrueSTUDIO

[동작]

타이밍 다이어그램
데이터 포맷

  • 16 비트 데이터 포맷 사용 (D15~D12 사용 X)
  • D11~D8 ADDRESS(명령어 역할), D7~D0 DATA(MSB to LSB, 해당 명령어 설정값)
  • 작동 시작 됐을 때, 모든 컨트롤 레지스터는 리셋, 디스플레이는 비어있는 상태이고 MAX7219는 셧다운 모드에 진입한다
  • 디스플레이를 사용하기 전에 디스플레이 드라이버를 프로그래밍해야한다
  • 그렇지 않으면, 첫번째 자리를 스캔하도록 설정되고 데이터 레지스터의 데이터를 디코딩하지 않으며 밝기 레지스터는 최소값으로 설정된다

- 레지스터 어드레스 맵

  • MAX7219에 전달할 16비트 데이터 중 상위 8비트에 사용되는 어드레스 목록 (명령어 역할)

- 디코드 모드

디코드 모드 레지스터

  • 디코드 모드 레지스터는 BCD 코드 B(0-9, E, H, L, P, -)를 설정하거나 각 자리에 대해 디코드 미사용 설정
  • 레지스터의 각 비트는 디스플레이 숫자 자리에 해당 (D0=디스플레이 첫째 자리, D1=둘째 자리, ...)
  • 로직 하이(1)는 Code B 디코딩을 선택하고 로직 로우(0)는 디코더를 우회한다
  • 코드B 디코드 모드가 사용될 때, 디코더는 숫자 레지스터 데이터의 하위 니블(D3-D0)만을 보고 D4-D6 비트는 무시한다
  • 소수점을 설정하는 D7은 디코더 설정에 대해 독립적이고 로직 1일 때 소수점이 켜진다
  • 디코드 미사용 설정을 한 뒤, 해당 디스플레이 자리의 데이터 비트 D7-D0은 MAX7219의 세그먼트 라인에 해당
  • (ex : 0x0900 을 전송해 디스플레이 모든 자리를 디코드 미사용으로 설정하고 0x0130 (Digit 0+Segement Line B,C)을 전송하면 디스플레이 첫번째 자리에 세그먼트 라인 B, C가 켜진다)

숫자 레지스터 데이터 / 왼쪽 : 디코드 사용, 오른쪽 : 디코드 미사용
디코드 미사용 모드에서 세그먼트 라인 설정

- 밝기 조절

밝기 강도 레지스터

  • 디스플레이 밝기는 Intensity 레지스터를 통해 디지털 방식으로 조절할 수 있다
  • 디스플레이 밝기의 디지털 컨트롤은 intensity 레지스터의 하위 니블로 제어되는 내부 PWM을 통해 제공된다
  • 모듈레이터 스케일은 RSET에 의해 설정된 최대 전류의 최대 31/32에서 1/32까지 16단계로 평균 세그먼트 전류를 조정한다

- 스캔 리미트 레지스터

스캔 리미트 레지스터

  • 스캔 리미트 레지스터는 디스플레이의 1~8번째 자리 중 몇개의 자리를 사용할지를 설정한다
  • 스캔된 숫자의 갯수는 디스플레이 밝기에 영향을 주기 때문에 스캔 리미트 레지스터를 디스플레이의 여백 부분으로 사용해서는 안된다 (선두의 의미없는 0을 감추는 것처럼)
  • 표에서 보이는 것처럼 두번째 이상의 자리를 사용하면서 하위 자리의 디스플레이를 미사용하는 것은 불가능하다
  • (사용 설정을 한 뒤, 해당 자리를 공백으로 채우는 것과는 다름)

- 디스플레이 테스트 레지스터

디스플레이 테스트 레지스터

  • 디스플레이 테스트 레지스터는 테스트 모드, 노멀 모드 설정을 할 수 있다
  • 디스플레이 테스트 모드는 모든 컨트롤 및 자리 레지스터(셧다운 레지스터 포함)를 변경이 아닌 재정의 해서 모든 LED를 켠다
  • 디스플레이 테스트 모드에선 8자리가 스캔되고 31/32 듀티 사이클을 가진다
  • 디스플레이 테스트 레지스터가 노멀 동작으로 재설정되기 전까지는 테스트 모드 유지

- No-Op 레지스터

  • No-Op 레지스터는 MAX7219를 직렬로 연결할 때 사용
  • 모든 디바이스의 LOAD/CS 인풋을 묶어 연결하고 DOUT을 인접한 디바이스의 DIN에 연결한다
  • DOUT은 CMOS 로직 레벨 출력으로 연속적으로 직렬 연결된 파트의 DIN을 손쉽게 구동한다
  • 사용 예) 네 개의 MAX 7219가 직렬 연결되어있고 네 번째 칩에 데이터를 쓰기 위해 원하는 16비트 워드를 전송한 다음 3개의 비작동 코드를 전송한다
  • LOAD/CS 가 HIGH가 될 때, 모든 디바이스의 데이터가 잠긴다.
  • 처음 세 개의 칩은 No-Op 명령어를 수신하고 네번째 디바이스는 목표한 데이터를 수신한다

[CUBE MX 설정]

SPI 설정 / 데이터 사이즈 16 Bits, 보드 레이트 8.0Mbits/s, Hardware NSS Output Signal 사용
SPI 인터럽트 활성화

  • STM32WBXX 의 경우, SPI1 보드 레이트는 APB2 Peripheral Clock을 기준으로 정해진다
  • 디폴트 설정인 APB2 Peripheral clock 32Mhz, SPI1 Prescaler 4 의 값으로 SPI1 보드 레이트는 8.0Mbits/s
  • MAX7219는 데이터를 수신하는 역할만 하므로 Transmit Only Master 선택
  • NSS - CS 역할 (Master일 경우에만 Output 사용 가능, 사용 보드의 경우 NSS핀으로 PA4 자동 사용 설정)
  • (Hardware NSS를 사용하지 않고 GPIO를 소프트웨어 컨트롤해 CS 라인을 제어해도 된다)

[코드]

- 정의

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

#define max7219_SPI hspi1		//MAX7219 통신에 사용되는 SPI를 사용하기 편하게 재정의
//HAL_SPI_Transmit_IT(&max7219_SPI, ...) = HAL_SPI_Transmit_IT(&hspi1, ...) (SPI1 사용)

#define max7219_No_Op_Mode 0x00	//No-Op 모드

#define max7219_Decode_Mode 0x09	//디코드 모드

#define max7219_Intensity_Mode 0x0A	//디스플레이 밝기 모드

#define max7219_Scan_Limit_Mode 0x0B	//스캔 리미트 모드

#define max7219_Display_Test_Mode 0x0F	//디스플레이 테스트 모드
#define max7219_Display_Test_Enter 1	//테스트 모드 진입
#define max7219_Display_Test_Exit 0		//테스트 모드 종료, 노멀 모드로 전환

#define max7219_Shutdown_Mode 0x0C	//셧다운 모드
#define max7219_Shutdown_Enter 0		//셧다운 모드 진입
#define max7219_Shutdown_Exit 1		//셧다운 모드 종료, 노멀 모드로 전환

#define max7219_blank 0x0F			//디코드 모드에서 디스플레이 공백 표현에 사용
/* USER CODE END PD */

- 명령 함수

/*
명령어와 명령어에 따른 설정값을 받아와 전송하는 함수
*/
static void max7219_cmd(int cmd, int data)	//cmd=ADDRESS(명령어 역할), data=명령어 설정값
{
	uint16_t write_buffer=0;	//MAX7219에 전송할 16비트 변수
    
	write_buffer=(cmd<<8)|data;		
	//전달받은 명령어는 상위 8비트, 명령어에 따른 설정값은 하위 8비트에 저장
    
	HAL_SPI_Transmit_IT(&max7219_SPI,(uint8_t *)&write_buffer,1);	//MAX7219에 전송

	while(HAL_SPI_GetState(&max7219_SPI)==HAL_SPI_STATE_BUSY_TX)
	{
		//전송 완료까지 대기
	}
}
  • 16비트 포맷을 사용해야 하므로 MAX7219에 전송할 16비트 변수를 선언
  • 명령어와 명령어에 따른 설정값을 받아와서 앞서 선언한 16비트 변수의 상위 8비트에는 명령어(ADDRESS)를 하위 8비트에는 데이터(명령어 설정값)을 입력한다
  • MAX7219의 모든 기능이 동일한 데이터 수신 방법을 사용하므로 이 함수만으로도 모든 기능을 사용할 수 있다

- 숫자 입력 함수

/*
숫자를 입력할 자리와 입력할 데이터를 받아와 전송하는 함수
단순히 명령어를 입력하는 것과 디스플레이에 표현할 숫자를 입력하는 것을 구분 짓기 위해 만든 것으로
데이터 전달 방식에서 max7219_cmd() 함수와의 차이는 없다
*/
static void max7219_write_value(int digit, int value, int decimal_point)
//digit=숫자를 입력할 자리(1~8), value=입력할 데이터, 소수점 표현 (0=미사용, 1=사용)
{
	uint16_t write_buffer=0;	//MAX7219에 전달할 16비트 변수 선언
    
    /*
    디코드 모드를 사용할 때, (-, E, H, L, P, ' ')은 아스키 코드값으로 10이 넘는 인티저 값을 갖는 것을 이용
    (value!=0x20) 은 디코드 미사용할 때, 세그먼트 라인 B를 표기하는데 문제가 생기는 것을 막기 위함
    (' ' 과 동일한 값을 같기 때문에 사용자가 0x20을 입력하면 ' ' 취급되어 실제론 0x0F가 입력된다)
    */
	if((20<value)&&(value!=0x20))
	{
		char w_char=(char)value;
		switch(w_char)
		{
			case '-' :
				value=0x0A;	//디코드 모드에서 '-' 를 표현하기 위한 레지스터 데이터 값
				break;
			case 'e' :
			case 'E' :
				value=0x0B;
				break;
			case 'h' :
			case 'H' :
				value=0x0C;
				break;
			case 'l' :
			case 'L' :
				value=0x0D;
				break;
			case 'p' :
			case 'P' :
				value=0x0E;
				break;
			case ' ' :
				value=0x0F;
				break;
			default :
				break;
		}
	}
	write_buffer=((digit+1)<<8)|value;
	//디스플레이의 자릿수는 0x01부터 시작해 0x08까지 사용

	if(decimal_point==1)
	{
		write_buffer|=0x80;
	}
	//소수점을 사용할 경우, 7번째 비트를 High(1)로 설정

	HAL_SPI_Transmit_IT(&max7219_SPI,(uint8_t *)&write_buffer,1);
	while(HAL_SPI_GetState(&max7219_SPI)==HAL_SPI_STATE_BUSY_TX)
	{

	}
}
  • 단순히 명령어 전달과 디스플레이 표현을 구분지어 사용하기 위해 선언한 함수
  • 전달하는 데이터의 크기 및 데이터 구조는 명령 함수와 동일하다
  • 소수점 표현의 경우, 7번 비트를 로직 High(1)로 설정해주면 된다
  • ex ) 디스플레이 2번째 자리에 2. 을 표현하기 위해선 (디스플레이 첫번째 자리 = Digit 0 이라 가정)
  • 상위 8비트 : 디스플레이 4번째 자리 Digit 3 = 0x04 (Digit0=0x01 부터 시작 (0x00 (X))
  • 하위 8비트 : 숫자 2 = 0x02, 소수점 = 0x70 => 0x72

- 초기화 예시

int main(void)
{
  	...
  max7219_cmd(max7219_Shutdown_Mode,max7219_Shutdown_Exit);	//셧다운 모드 종료, 노멀 작동 시작
  max7219_cmd(max7219_Scan_Limit_Mode,0x07);	//스캔 리미트 모드, 0x07=디스플레이 8자리 모두 사용
  max7219_cmd(max7219_Decode_Mode, 0xFF);	//디코드 모드, 디스플레이 8자리 모두 디코드 모드로 설정
  max7219_cmd(max7219_Intensity_Mode, 0x08);	//디스플레이 밝기, 중간으로 설정 (0x00~0x0F 16단계)
  
}
  • 작동이 시작 됐을 때  MAX7219는 셧다운 모드에 진입한다고 되있었으므로 셧다운 모드 종료를 먼저 실행
  • 디스플레이를 사용하기 전에 프로그래밍을 하지 않을 경우, 첫째 자리를 스캔하도록 설정되고 데이터 레지스터의 데이터를 디코딩하지 않으며 밝기 레지스터는 최소값으로 설정되므로
  • 스캔 리미트 모드에서 디스플레이 8자리 모두 사용 설정 (0x00~0x07)
  • 디코드 모드에서 디스플레이 8자리 모두 디코드 모드 사용 설정 (데이터 비트=디스플레이 자릿수, 1=디코드 사용)
  • 디스플레이 밝기 모드에서 16단계 중 9단계로 설정

- 단순 사용 예시

int main(void)
{
	...
  /* USER CODE BEGIN 2 */
  
  max7219_cmd(max7219_Shutdown_Mode,max7219_Shutdown_Exit);
  max7219_cmd(max7219_Scan_Limit_Mode,0x07);
  max7219_cmd(max7219_Decode_Mode, 0x00);	//디스플레이 모든 자리 디코드 미사용
  max7219_cmd(max7219_Intensity_Mode, 0x08);
  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    
	  max7219_cmd(max7219_Decode_Mode, 0);	//모든 자리 디코드 미사용
      
	  for(uint8_t i=0;i<8;i++)	//디스플레이 모든 자리 공백으로 초기화
	  {
	  	max7219_write_value(i,0,0);
	  	//디코드 모드 공백 : 0x0F, 디코드 미사용 공백 : 0x00
  	  }
  
 	  for(int i=0;i<8;i++)
  	  {
	  	  int k=0;
	  	  for(int j=0;j<8;j++)
	  	  {
		  	  max7219_write_value(i,k|=(0x01)<<j,0)	
		  	  //비트0 부터 MSB로 1비트씩 비트 시프트 및 OR 연산으로 해당 자리의 모든 세그먼트 라인을 켬
		  	  HAL_Delay(100);
	  	  }
	  }
      
      
	  max7219_cmd(max7219_Decode_Mode,0xFF);	//모든 자리 디코드 사용
      
	  for(uint8_t i=0;i<8;i++)
	  {
		  max7219_write_value(i,max7219_blank,0);	
		  //디스플레이 모든 자리 공백으로 초기화 (DATA : 0x0F)
	  }
      
	  for(uint8_t i=0;i<8;i++)
	  {
		  max7219_write_value(i,'-',1);	//디스플레이 -. (소수점 표기 사용)으로 채움
		  HAL_Delay(500);
	  }
      
	  for(uint8_t i=0;i<8;i++)
	  {
		  max7219_write_value(i,i,0);	//디스플레이 자릿수와 일치하는 숫자로 채움
		  HAL_Delay(500);
	  }
	  max7219_write_value(7,'H',0);
	  HAL_Delay(500);
	  max7219_write_value(6,'E',0);
	  HAL_Delay(500);
	  max7219_write_value(5,'L',0);
	  HAL_Delay(500);
	  max7219_write_value(4,'P',0);
	  HAL_Delay(500);
  }
  /* USER CODE END 3 */
}
  • 디스플레이 모든 자리 사용, 디코드 미사용, 밝기 9단계로 초기화
  • 디스플레이 모든 자리를 공백으로 초기화 (디코드 미사용일 때 공백을 표현하기 위한 데이터값은 0x00)
  • 디스플레이 0번부터 7번까지 순차적으로 세그먼트 라인을 하나씩 채워나감
  • 디스플레이 모든 자리를 디코드 사용으로 바꾼 뒤 공백으로 초기화 (디코드 모드 공백 데이터 : 0x0F)
  • (디코드 사용/미사용 전환을 해도 각 자리의 레지스터 데이터는 유지된 상태로 존재하기 때문에 디코드 사용/미사용에 따라 디스플레이 표현만 변한다)
  • 디스플레이 0번부터 7번까지 순차적으로 '-.' 문자를 표시
  • 디스플레이 자리와 동일한 숫자값을 디스플레이 0번부터 7번까지 순차적으로 표현
  • 디스플레이 7번부터 4번까지 순차적으로 H, E, L, P 문자 데이터 입력

디스플레이의 5번째 자리에 숫자 5를 입력했을 때

  • 디스플레이 자리는 0x01(=0번째)부터 시작하므로 상위 8비트 0x06은 Digit 5(다섯번째 자리)를 ADDRESS로 사용했음을 의미한다
  • 하위 8비트는 0x05이므로 디스플레이 다섯번째 자리에 숫자 5가 표현된다

+ Recent posts