- 통신 방법 : 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 설정]
- 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 문자 데이터 입력
- 디스플레이 자리는 0x01(=0번째)부터 시작하므로 상위 8비트 0x06은 Digit 5(다섯번째 자리)를 ADDRESS로 사용했음을 의미한다
- 하위 8비트는 0x05이므로 디스플레이 다섯번째 자리에 숫자 5가 표현된다
'STM32' 카테고리의 다른 글
STM32 - PWM 이용 4 PIN PWM FAN 제어 (2) | 2020.07.31 |
---|---|
STM32 - SPI 이용 ST7735 LCD 드라이버 제어 (0) | 2020.06.21 |
STM32 - I2C 통신 MLX90614 적외선 비접촉 온도 측정 센서 (2) | 2019.12.10 |
STM32 - UART 기반 PMS7003 먼지 센서 제어 (17) | 2019.12.04 |
P-NUCLEO-WB55 보드 무선 통신 사용 설정 (1) | 2019.10.16 |