STM32F103RB – DS1302

  • Post author:
  • Post category:STM32

출처: https://m.blog.naver.com/kiatwins/221124103717

CubeMX로 아두이노 D5~7번 3개의 핀을 출력으로 설정하고 프로젝트를 생성하고 아래 코드를 넣어주면 됩니다.

시간설정은 터미널에서 년월일시분초 12자를 입력하면 수신인터럽트로 처리해서 RTC 레지스터에 저장이 됩니다. stm32f1xxit.c에 있는 USART2_IRQHandler 함수는 지우거나 주석처리하면 됩니다.
TrueStudio에서 한글을 처리하려면 편집–인코딩설정–UTF-8로 에디터 설정을 바꿔주면 제대로 출력이 됩니다. UTF-8로 설정했기 때문에 한글 1글자는 3바이트로 처리가 됩니다.
DS1302

출처: https://wowon.tistory.com/271

– 통신방식

 

DS1302로부터 시간을 write하거나 read할 때 통신을 해야합니다. 통신을 하기위해서 MCU랑 SCLK, I/O, CE핀이 연결이 되야 합니다. 통신방식이 SPI랑 비슷합니다. SCLK는 클럭핀이고 I/O핀은 data핀이고 CE핀은 통신 이네이블 핀이라서 통신을할때는 HIGH로 유지되어야 합니다.

– WRITE/READ 하기

 

ds1302에 write/read하려면 위와 같은 파형을 만들어야합니다. write한다는건 ds1302에 특별기능을 write하거나 원하는 시간을 write하는 동작입니다.read한다는건 ds1302에서 시간을 읽는 동작입니다.
앞쪽에 R/W’가 있는데 READ동작이면 1이고 WRITE동작이면 0입니다. 그리고 A0~A4가 있는데 주소값이랑 비슷한 느낌이고 A0~A4값을 바꿔서 seconds를 설정하거나 minutes를 설정하거나 합니다. R/C가 있는데 RAM/CLOCK,CALENDAR을 의미합니다. RAM을 제어하려면 1, CLOCK,CALENDAR을 제어하려면 0으로 설정하면 됩니다.
D0~D7는 데이터비트 입니다.

 

처음 목표였던 '초'를 읽으려면 0x81을 LSB로 보낸 다음에 들어오는값을 읽으면 됩니다. 들어오는값도 LSB로 옵니다.

이제 CE,SCLK,I/O핀을 GPIO제어해서 그림1과같은 파형을 만들어야 합니다. 먼저 WRITE파형부터 어떤식으로 만들어야 하는지 알아보겠습니다.

 

그림4는 WRITE파형입니다. 통신을 할 때 CE핀의 상태를 LOW에서 HIGH로 해놔야 합니다.
빨강 동그라미를 보면 클럭이 LOW에서 HIGH가 됩니다. 그때 DS1302는 I/O핀의 상태를 읽습니다. 클럭에 화살표가 있는 방향에서 DS1302가 데이터를 READ한다고 보면 됩니다. (MCU : Write, DS1302 : Read)
처음 클럭8개는 뒤에 나올 클럭8개가 어떤 데이터인지 알려주는 역할을 합니다.
그러므로 코드의 흐름은 아래처럼 하면 됩니다.

여기서 1번,7번에서 I_O핀을 OUTPUT설정하는 부분이 있는데 하나의 핀이 INPUT/OUTPUT역할을 하므로 OUTPUT설정을 먼저 해준겁니다.

 

그림5는 READ 파형입니다. 앞에클럭8개는  write때랑 방식이 같습니다. 빨강동그라미를 보면 READ는 클럭이 HIGH에서 LOW로 될 때 DS1302가 write합니다. (MCU : Read, DS1302 : Write)
코드의 흐름은 아래처럼 하면 됩니다.

여기서 중요한점은 7번에서 I_O핀을 INPUT으로 설정해야 한다는 점입니다.

사용하는 MCU는 NUCLEO-F103RB 입니다. 먼저 GPIO설정을 해줍니다. DS1302랑 통신하기위해서는 IO포트 3개가 필요합니다.

그 다음에 DS1302를 write/read하기위해서 데이터시트에 나와있는 파형에 맞게 코드를 작성해줍니다

 

먼저 write 부터 알아보겠습니다

 

위의 과정에서 2~6번 과정을 함수로 만들어보겠습니다

매개변수들은 SCLK, RST, IO핀에대한것들이고 value는 write할 값입니다.

다른코드는 어려운건없고 if(((value>>i) & 0x01) ? 1 : 0)에대해 적어보겠습니다.
DS1302는 LSB타입으로 데이터를 보내야합니다. 아래의 표를 보면 second를 write하는 부분을 보면 0x80을 보내야합니다. 근데 파형을 보면 [R/W
A0 A1 A2 A3 A4 R/C’ 1]이라고 적혀있습니다. 0x80을 LSB로 보내야 합니다. 매개변수에 0x80을 넣고 파형에서는 0000 0001이라고 나오게하기위해서 if(((value>>i) & 0x01) ? 1 : 0) 을 했습니다.
i = 0 일때 value >> 0 이고 가장작은비트의 값을 검사해서 HIGH or LOW 설정합니다.
i = 1 일때 value >> 1 을 해서 그 다음 비트의 값을 검사해서 HIGH or LOW 설정합니다.
이런 방식으로 한다면 매개변수에 0x80을 넣어도 파형은 0000 0001이 나오게 됩니다.

아래의 코드를 넣어서 파형을 찍어보겠습니다.

이제 read를 해보겠습니다

 

위의 과정에서 7~11번 과정을 함수로 만들어보겠습니다

read를 하려면 DS1302로부터 읽어야 하므로 먼저 IO를 input으로 바꿔야합니다. 그 다음 읽을때도 LSB이므로 value |= (currentbit << i)를 해서 먼저 읽는 비트를 가장작은비트에 저장합니다.

아래의 코드의 파형을 보겠습니다. (k는 uint8_t형 변수입니다)

 

사실 write없이 read만 하면 의미가 없습니다. 데이터시트에 나와있는 파형을 보면 먼저 write를 하고 write해서 나오는 파형을 읽습니다.

이제 read / write파형을 만들 수 있으니 DS1302로부터 ‘초’단위만 읽어서 시리얼모니터로 값을 확인하는 작업을 할 수있습니다.
먼저 CLOCK을 사용한다고 WRITE를 해줘야 합니다.

 

CLOCK HALT FLAG를 start하기 위해서 CH에 0을 write 해줘야 합니다. second는 설정하지않고 CLOCK HALT FLAG를 start하기위해서 0x80 write , 0x00 write해주면 됩니다.

 

HALT를 함수로 만들었습니다. 매개변수 flag가 1이면 CLOCK이 멈추고 0이면 CLOCK이 start됩니다.

그 다음 초를 읽기위해서 READ를 해주면 됩니다. second를 read하기 위해서 0x81 write, read 하면 됩니다.

초를 읽는 코드입니다. 1초에 한번씩 읽은값을 printf 해주고 있습니다. 근데 여기서 중요한게 printf의 표시형식이 %x(16진수)입니다. 10진수로 출력안하고 16진수로 출력했는데 그 이유는 읽고나면 읽은 seconds 데이터 포맷이 16진수이므로 16진수로 printf했습니다.

예시로 파형몇개만 보겠습니다.

아래의 파형은 0x81로 read를하고 데이터를 읽었는데 읽은 데이터가 0x64이므로  0x26입니다.

 

아래의 파형은 read한값이 0xE4이므로 0x27입니다.

 

그래서 printf를 하면 second : 26  second : 27라고 나오게 됩니다.

최종 결과입니다. 숫자가 1씩 증가하는걸 볼 수 있습니다

source code: STM32F103RB_DS1302-main

2편에서 단순히 초만 읽었는데, 3편에서는 시간,분,초를 설정하고 시간, 분, 초를 읽어보겠습니다

-읽기

2편에서 만들었던 commandWirte함수와 commandRead함수를 이용해서 시간,분,초를 읽고 배열에 저장했습니다

-쓰기

쓰기를 하기전에 먼저 만들어야 할 함수가 있습니다. 위의 그림에서 seconds를 write하려면 값을 bit6~bit4는 10의자리, bit3~bit0은 1의자리를 write해야합니다.

decToformat(20)을 하면 0x20가 return 됩니다.

그리고 hours 설정하는걸 보면 12시간기준 or 24시간기준을 선택할수있는데 여기서는 24시간기준으로 시간을 설정하겠습니다.

결과

시간을 설정하고 uart로 값을 출력했습니다

시간/분/초 외에도 년도,월,요일도 같은 방식으로 설정 가능합니다

소스코드:https://github.com/yhunterr/STM32F103RB_DS1302/tree/main/DS1302_SECOND

또 다른 소스코드
https://github.com/julgonmej/stm32f7-ds1302-lib [zip]