출처: https://m.blog.naver.com/kiatwins/221124103717
CubeMX로 아두이노 D5~7번 3개의 핀을 출력으로 설정하고 프로젝트를 생성하고 아래 코드를 넣어주면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
/* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_hal.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart2; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ int _write(int32_t file, uint8_t *ptr, int32_t len){ HAL_UART_Transmit(&huart2, ptr, len, 10); return len; } #define delay_ms HAL_Delay #define SYS_CLOCK 72 #define SYSTICK_LOAD 71999 uint32_t millis_cnt=1; uint32_t millis(){ return millis_cnt; } uint32_t micros(){ return (millis_cnt&0x3FFFFF)*1000 + (SYSTICK_LOAD-SysTick->VAL)/SYS_CLOCK; } void delay_us(uint32_t us){ uint32_t temp = micros(); uint32_t comp = temp + us; uint8_t flag = 0; while(comp > temp){ uint32_t mil = millis_cnt; if(((mil&0x3FFFFF)==0)&&(flag==0)){ flag = 1; } if(flag) temp = micros() + 0x400000UL * 1000; else temp = micros(); } } #define SCLK_HI HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, SET) // D5 GPIOB GPIO_PIN_4 #define SCLK_LO HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, RESET) #define IO_HI HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, SET) // D6 GPIOB GPIO_PIN_10 #define IO_LO HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, RESET) #define CE_HI HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, SET) // D7 GPIOA GPIO_PIN_8 #define CE_LO HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, RESET) #define IO_READ HAL_GPIO_ReadPin(GPIOB , GPIO_PIN_10) #define IO_OUTPUT GPIOB->CRH=(GPIOB->CRH&0xFFFFF0FF)|(3<<(2*4)); // General purpose output mode 50 MHz. #define IO_INPUT GPIOB->CRH=(GPIOB->CRH&0xFFFFF0FF)|(4<<(2*4)); // Input mode (reset state) uint8_t year, month, date, day, hour, minute, sec; //char day_char[8][4] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"}; char day_char[8][4] = {"일", "월", "화", "수", "목", "금", "토", "일"}; void CLK_Pulse(void){ delay_us(1); SCLK_HI; delay_us(1); SCLK_LO; } void data_write(uint8_t addr, uint8_t data){ IO_OUTPUT; CE_HI; delay_us(1); for(uint8_t i=0; i<8; i++){ if(addr&(1<<i)) IO_HI; else IO_LO; CLK_Pulse(); } for(uint8_t i=0; i<8; i++){ if(data&(1<<i)) IO_HI; else IO_LO; CLK_Pulse(); } CE_LO; } uint8_t data_read(uint8_t addr){ uint8_t data=0; IO_OUTPUT; CE_HI; delay_us(1); for(uint8_t i=0; i<8; i++){ if(addr&(1<<i)) IO_HI; else IO_LO; CLK_Pulse(); } IO_INPUT; for(uint8_t i=0; i<8; i++){ if(IO_READ!=0) data|=(1<<i); CLK_Pulse(); } CE_LO; return data; } void RTC_read(void){ sec = data_read(0x81); // 0~59 minute = data_read(0x83); // 0~59 hour = data_read(0x85); // 0~23 date = data_read(0x87); // 1~31 month = data_read(0x89); // 1~12 day = data_read(0x8B); // 1~7 year = data_read(0x8D); // 0~99 } uint8_t DEC_to_BCD(uint8_t data) { uint8_t temp=((data/10)*16)+(data%10); return temp; } void RTC_write(uint8_t year, uint8_t month, uint8_t date, uint8_t day, uint8_t hour, uint8_t minute, uint8_t sec){ data_write(0x80, DEC_to_BCD(sec)); data_write(0x82, DEC_to_BCD(minute)); data_write(0x84, DEC_to_BCD(hour)); data_write(0x86, DEC_to_BCD(date)); data_write(0x88, DEC_to_BCD(month)); data_write(0x8A, day); data_write(0x8C, DEC_to_BCD(year)); data_write(0x90, 0); // TRICKLE-CHARGE REGISTER } uint8_t day_of_week(uint8_t y, uint8_t m, uint8_t d) { uint8_t t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; y -= m < 3; return (y + y / 4 - y / 100 + y / 400 + t[m - 1] + d) % 7; } void USART2_IRQHandler(void){ static uint8_t rx_buf[20]; static uint8_t cnt=0; uint8_t receive = (uint8_t)USART2->DR; if((receive=='\r')||(receive=='\n')){ if(cnt==12){ for(uint8_t i=0; i<12; i++) rx_buf[i]&=0x0F; data_write(0x80, DEC_to_BCD((rx_buf[10]*10)+rx_buf[11])); // sec data_write(0x82, DEC_to_BCD((rx_buf[8]*10)+rx_buf[9])); // minute data_write(0x84, DEC_to_BCD((rx_buf[6]*10)+rx_buf[7])); // hour uint8_t dd = (rx_buf[4]*10) + rx_buf[5]; uint8_t mm = (rx_buf[2]*10) + rx_buf[3]; uint8_t yy = (rx_buf[0]*10) + rx_buf[1]; data_write(0x86, DEC_to_BCD(dd)); // date data_write(0x88, DEC_to_BCD(mm)); // month data_write(0x8A, DEC_to_BCD(DEC_to_BCD(day_of_week(yy, mm, dd)))); // day data_write(0x8C, DEC_to_BCD(yy)); // year } cnt=0; } else{ if(cnt<16) rx_buf[cnt++] = receive; } } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ //RTC_write(17, 10, 18, 3, 2, 9, 0); // year, month, date, day, hour, minute, sec __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); uint32_t current = millis(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(millis() >= (current+1000)){ current = millis(); RTC_read(); printf("20%02x/%02x/%02x[%s] %02x:%02x:%02x \r\n", year, month, date, (char *)&day_char[day], hour, minute, sec); } delay_ms(1); } /* USER CODE END 3 */ } |
출처: 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
초기상태 CE핀 : LOW SCK핀 : LOW IO핀 : 사용자설정 * Write 1. CE핀 -> HIGH세팅 2. I_O핀 = OUTPUT 설정 3. I_O핀 -> HIGH or LOW 4. SCLK핀 -> HIGH 5. SCLK핀 -> LOW 6. 3~5번 과정 7번 더 반복 7 I_O핀 = OUTPUT 설정 8. I_O핀 -> HIGH or LOW 9. SCLK핀 -> HIGH 10. SCLK핀 -> LOW 11. 8~10번 과정 7번 더 반복 12. CE핀 -> LOW세팅 |
여기서 1번,7번에서 I_O핀을 OUTPUT설정하는 부분이 있는데 하나의 핀이 INPUT/OUTPUT역할을 하므로 OUTPUT설정을 먼저 해준겁니다.
그림5는 READ 파형입니다. 앞에클럭8개는 write때랑 방식이 같습니다. 빨강동그라미를 보면 READ는 클럭이 HIGH에서 LOW로 될 때 DS1302가 write합니다. (MCU : Read, DS1302 : Write)
코드의 흐름은 아래처럼 하면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
초기상태 CE핀 : LOW SCK핀 : LOW IO핀 : 사용자설정 * Read 1. CE핀 -> HIGH세팅 2. I_O핀 = OUTPUT 설정 3. I_O핀 -> HIGH or LOW 4. SCLK핀 -> HIGH 5. SCLK핀 -> LOW 6. 3~5번 과정 7번 더 반복 7. I_O핀 = INPUT 설정 8. I_O핀 READ 9. SCLK핀 -> HIGH 10. SCLK핀 -> LOW 11. 8~10번 과정 7번 더 반복 12. CE핀 -> LOW세팅 |
여기서 중요한점은 7번에서 I_O핀을 INPUT으로 설정해야 한다는 점입니다.
사용하는 MCU는 NUCLEO-F103RB 입니다. 먼저 GPIO설정을 해줍니다. DS1302랑 통신하기위해서는 IO포트 3개가 필요합니다.
그 다음에 DS1302를 write/read하기위해서 데이터시트에 나와있는 파형에 맞게 코드를 작성해줍니다
먼저 write 부터 알아보겠습니다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
초기상태 CE핀 : LOW SCK핀 : LOW IO핀 : 사용자설정 * Write 1. CE핀 -> HIGH세팅 2. I_O핀 = OUTPUT 설정 3. I_O핀 -> HIGH or LOW 4. SCLK핀 -> HIGH 5. SCLK핀 -> LOW 6. 3~5번 과정 7번 더 반복 7 I_O핀 = OUTPUT 설정 8. I_O핀 -> HIGH or LOW 9. SCLK핀 -> HIGH 10. SCLK핀 -> LOW 11. 8~10번 과정 7번 더 반복 12. CE핀 -> LOW세팅 |
위의 과정에서 2~6번 과정을 함수로 만들어보겠습니다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void commandWrite(GPIO_TypeDef *GPIO_SCLK, uint16_t GPIO_Pin_SCLK, GPIO_TypeDef *GPIO_I_O, uint16_t GPIO_Pin_I_O,uint8_t value) { /* I_O PORT OUTPUT SETTING */ GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_Pin_I_O; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIO_I_O, &GPIO_InitStruct); int i; /* WRITE SETTING */ for(i=0;i<8;i++) //LSB { if(((value>>i) & 0x01) ? 1 : 0 ) HAL_GPIO_WritePin(GPIO_I_O, GPIO_Pin_I_O, 1); else HAL_GPIO_WritePin(GPIO_I_O, GPIO_Pin_I_O, 0); HAL_GPIO_WritePin(GPIO_SCLK, GPIO_Pin_SCLK, 1); HAL_GPIO_WritePin(GPIO_SCLK, GPIO_Pin_SCLK, 0); } } |
매개변수들은 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이 나오게 됩니다.
아래의 코드를 넣어서 파형을 찍어보겠습니다.
1 2 3 4 5 6 7 |
{ HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x80); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); } |
이제 read를 해보겠습니다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
초기상태 CE핀 : LOW SCK핀 : LOW IO핀 : 사용자설정 * Read 1. CE핀 -> HIGH세팅 2. I_O핀 = OUTPUT 설정 3. I_O핀 -> HIGH or LOW 4. SCLK핀 -> HIGH 5. SCLK핀 -> LOW 6. 3~5번 과정 7번 더 반복 7. I_O핀 = INPUT 설정 8. I_O핀 READ 9. SCLK핀 -> HIGH 10. SCLK핀 -> LOW 11. 8~10번 과정 7번 더 반복 12. CE핀 -> LOW세팅 |
위의 과정에서 7~11번 과정을 함수로 만들어보겠습니다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
uint8_t commandRead(GPIO_TypeDef *GPIO_SCLK, uint16_t GPIO_Pin_SCLK, GPIO_TypeDef *GPIO_I_O, uint16_t GPIO_Pin_I_O) { /* I_O PORT INPUT SETTING */ GPIO_InitTypeDef GPIO_InitStruct = {0}; HAL_GPIO_WritePin(GPIO_I_O, GPIO_Pin_I_O, 0); GPIO_InitStruct.Pin = GPIO_Pin_I_O; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIO_I_O, &GPIO_InitStruct); uint8_t value=0; uint8_t currentBit = 0; int i; /* INPUT SETTING */ for(i=0;i<8;i++) { currentBit = HAL_GPIO_ReadPin(GPIO_I_O, GPIO_Pin_I_O); value |= (currentBit<<i); HAL_GPIO_WritePin(GPIO_SCLK, GPIO_Pin_SCLK, 1); HAL_GPIO_WritePin(GPIO_SCLK, GPIO_Pin_SCLK, 0); } return value; } |
read를 하려면 DS1302로부터 읽어야 하므로 먼저 IO를 input으로 바꿔야합니다. 그 다음 읽을때도 LSB이므로 value |= (currentbit << i)를 해서 먼저 읽는 비트를 가장작은비트에 저장합니다.
아래의 코드의 파형을 보겠습니다. (k는 uint8_t형 변수입니다)
1 2 3 4 5 6 7 |
{ HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); k = commandRead(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); } |
사실 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해주면 됩니다.
1 2 3 4 5 6 7 8 9 |
void DS1302_HALT(GPIO_TypeDef *GPIO_SCLK, uint16_t GPIO_Pin_SCLK, GPIO_TypeDef *GPIO_I_O, uint16_t GPIO_Pin_I_O, GPIO_TypeDef *GPIO_CE, uint16_t GPIO_Pin_CE, uint8_t flag) { HAL_GPIO_WritePin(GPIO_CE, GPIO_Pin_CE, 1); commandWrite(GPIO_SCLK, GPIO_Pin_SCLK, GPIO_I_O, GPIO_Pin_I_O, 0x80); commandWrite(GPIO_SCLK, GPIO_Pin_SCLK, GPIO_I_O, GPIO_Pin_I_O, 0x00 | flag<<7); HAL_GPIO_WritePin(GPIO_CE, GPIO_Pin_CE, 0); } |
HALT를 함수로 만들었습니다. 매개변수 flag가 1이면 CLOCK이 멈추고 0이면 CLOCK이 start됩니다.
그 다음 초를 읽기위해서 READ를 해주면 됩니다. second를 read하기 위해서 0x81 write, read 하면 됩니다.
초를 읽는 코드입니다. 1초에 한번씩 읽은값을 printf 해주고 있습니다. 근데 여기서 중요한게 printf의 표시형식이 %x(16진수)입니다. 10진수로 출력안하고 16진수로 출력했는데 그 이유는 읽고나면 읽은 seconds 데이터 포맷이 16진수이므로 16진수로 printf했습니다.
1 2 3 4 5 6 7 8 9 10 |
{ HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x81); k = commandRead(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); printf ("second : %x \n", k); HAL_Delay(1000); } |
예시로 파형몇개만 보겠습니다.
아래의 파형은 0x81로 read를하고 데이터를 읽었는데 읽은 데이터가 0x64이므로 0x26입니다.
아래의 파형은 read한값이 0xE4이므로 0x27입니다.
그래서 printf를 하면 second : 26 second : 27라고 나오게 됩니다.
최종 결과입니다. 숫자가 1씩 증가하는걸 볼 수 있습니다
source code: STM32F103RB_DS1302-main
2편에서 단순히 초만 읽었는데, 3편에서는 시간,분,초를 설정하고 시간, 분, 초를 읽어보겠습니다
-읽기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void readTime(uint8_t *time) { //array : 0: seconds, 1: minutes, 2: hours //seconds read HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x81); time[0] = commandRead(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); // minutes read HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x83); time[1] = commandRead(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); // hours read HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x85); time[2] = commandRead(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); } |
2편에서 만들었던 commandWirte함수와 commandRead함수를 이용해서 시간,분,초를 읽고 배열에 저장했습니다
-쓰기
쓰기를 하기전에 먼저 만들어야 할 함수가 있습니다. 위의 그림에서 seconds를 write하려면 값을 bit6~bit4는 10의자리, bit3~bit0은 1의자리를 write해야합니다.
1 2 3 4 5 6 |
uint8_t decToformat(uint8_t c) { return (c/10)<<4 | (c%10); } |
decToformat(20)을 하면 0x20가 return 됩니다.
그리고 hours 설정하는걸 보면 12시간기준 or 24시간기준을 선택할수있는데 여기서는 24시간기준으로 시간을 설정하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds) { //second HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x80); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, decToformat(seconds)); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); //minutes HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x82); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, decToformat(minutes)); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); //hours HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 1); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, 0x84); commandWrite(SCLK_GPIO_Port, SCLK_Pin, I_O_GPIO_Port, I_O_Pin, decToformat(hours)); HAL_GPIO_WritePin(CE_GPIO_Port, CE_Pin, 0); } |
결과
시간을 설정하고 uart로 값을 출력했습니다
시간/분/초 외에도 년도,월,요일도 같은 방식으로 설정 가능합니다
소스코드:https://github.com/yhunterr/STM32F103RB_DS1302/tree/main/DS1302_SECOND