재료별 리스트

온도를 디스플레이에 표시하는 것 까지 완료하였습니다. 이제는 설정 온도를 재료별로 리스트를 만들고, 버튼을 누르면 설정바뀌고 화면에 표시하는 코드를 작성하는 것 이 목표입니다.
먼저 재료별로 온도, 속도 항목을 포함할 수 있는 구조체를 선언 과 초기화를 해주는 코드를 추가합니다.

1int material_index = 0; // 재료 구조체 배열의 위치를 가리키는 인덱스
2int setTemperature = 0; // 설정된 온도
3
4struct setting {
5    int temperature;
6    char* materialName;
7};
8
9struct setting materials[] = {{0, "OFF"}, {60, "PCL"}, {200, "PLA"}};
구조체에는 서로 다른 자료형을 포함할 수 있습니다. 따라서 구조체 배열을 통해
OFF 일 경우 설정온도와 속도가 0
PCL 재료일 경우 온도는 50, 속도는 100
PLA 재료일 경우 온도는 200, 속도는 90
으로 설정이 입력된 것입니다.

필요한 변수들도 추가로 작성되었습니다. 구조체의 값을 저장할 전역변수를 선언 하였습니다.
위의 코드를 이전 스텝의 코드에 추가하면, 아래와 같습니다.

  1#include "ssd1306.h" // 라이브러리 포함
  2
  3#define BTN_A           8     // A버튼
  4#define BTN_B           7     // B버튼
  5#define BTN_C           11    // C버튼
  6#define BTN_D           12    // D버튼
  7
  8#define MOTOR_EN        5     // 모터 활성화 핀
  9#define MOTOR_DIR       6     // 모터 방향 핀
 10#define MOTOR_SPEED     10    // 모터 속도 핀
 11
 12#define HEATER_EN       9     // 열선 핀
 13
 14#define TEMP_IN         A0    // 온도 읽는 핀
 15
 16#define VALUE_TEMPTB    0     // 온도 테이블의 신호 값 인덱스
 17#define CELSIUS_TEMPTB  1     // 온도 테이블의 온도 값 인덱스
 18
 19#define MATERIAL_COUNT  3     // material 구조체 배열의 갯수
 20
 21String strToShow; // 디스플레이에 보여줄 문자열을 저장하는 변수
 22
 23int curTemp = 0; // 현재온도
 24
 25long timeInterval  = millis(); // 50ms 에 1회씩 작동하기 위한 시간 변수
 26
 27int material_index = 0; // 재료 구조체 배열의 위치를 가리키는 인덱스
 28int setTemperature = 0; // 설정된 온도
 29
 30// 온도, 속도, 재료명을 포함한 구조체 선언
 31struct setting {
 32    int temperature;
 33    char* materialName;
 34};
 35
 36struct setting materials[] = {{0, "OFF"}, {60, "PCL"}, {200, "PLA"}};
 37
 38/*
 39 *  온도 테이블 배열
 40 *  첫번째 항목은 신호 값, 두번째 항목은 온도 값
 41 */
 42int temptable[23][2] = {
 43    {1023,0},
 44    {1022,10},
 45    {1020,20},
 46    {1016,30},
 47    {1011,40},
 48    {1009,50},
 49    {1006,60},
 50    {1004,70},
 51    {1000,80},
 52    {990,90},
 53    {983,100},
 54    {976,110},
 55    {972,120},
 56    {964,130},
 57    {955,140},
 58    {942,150},
 59    {929,160},
 60    {910,170},
 61    {895,180},
 62    {864,190},
 63    {839,200},
 64    {800,210},
 65    {744,220}
 66};
 67
 68/*
 69 * 입력받은 문자를 디스플레이 좌표에 표시
 70 */
 71void showTextToScreen(int x, int y, String text)
 72{
 73    text = text + "\n";
 74    char ch[10];
 75    text.toCharArray(ch,text.length());
 76    ssd1306_printFixedN(x, y, ch, STYLE_NORMAL, FONT_SIZE_2X);
 77}
 78
 79/*
 80 * 온도를 읽고, 정확한 온도로 계산 후 결과 값을 화면에 표시하고 반환하는 함수
 81 * VALUE_TEMPTB = 0, CELSIUS_TEMPTB = 1 으로 온도표의 각 항목을 지시함
 82 */
 83int getTemperature()
 84{
 85    float ratioTemp;
 86    float tempADU = analogRead(A0);
 87    int result;
 88
 89    for(int i=1; i<23; i++){
 90        if(tempADU >= temptable[i][VALUE_TEMPTB])
 91        {
 92            ratioTemp = (tempADU - temptable[i][VALUE_TEMPTB])/(temptable[i-1][VALUE_TEMPTB] - temptable[i][VALUE_TEMPTB]);
 93
 94            result = temptable[i][CELSIUS_TEMPTB] - ratioTemp*(temptable[i][CELSIUS_TEMPTB] - temptable[i-1][CELSIUS_TEMPTB]);
 95
 96            strToShow = String(result);
 97
 98            showTextToScreen(0,16,strToShow);
 99
100            return result;
101        }
102    }
103
104    return ;
105}
106
107void setup()
108{
109    pinMode(BTN_A, INPUT_PULLUP);
110    pinMode(BTN_B, INPUT_PULLUP);
111    pinMode(BTN_C, INPUT_PULLUP);
112    pinMode(BTN_D, INPUT_PULLUP);
113
114    pinMode(MOTOR_EN, OUTPUT);
115    pinMode(MOTOR_DIR, OUTPUT);
116    pinMode(MOTOR_SPEED, OUTPUT);
117
118    pinMode(HEATER_EN, OUTPUT);
119
120    digitalWrite(MOTOR_EN, HIGH); // 모터 활성화
121
122    ssd1306_128x32_i2c_init(); // 32로 변경
123    ssd1306_fillScreen(0x00);  // 화면 초기화
124    ssd1306_setFixedFont(ssd1306xled_font6x8); // 폰트 설정
125    ssd1306_flipHorizontal(1); // x 화면 대칭 회전
126    ssd1306_flipVertical(1);   // y 화면 대칭 회전
127}
128
129void loop()
130{
131    if(millis() - timeInterval > 50)
132    {
133        curTemp = getTemperature();
134
135        timeInterval = millis();
136    }
137}

구조체 선언 과 초기화를 하였고, getTemperature 함수의 온도가 표시되는 좌표 위치도 조정하였습니다.
이어서 materials 의 값들을 디스플레이에 표시해보도록 하고
materials 의 현재 인덱스의 값을 디스플레이에 표시해주는 함수를 만들어 보겠습니다.
※ 작성된 코드가 길기 때문에 추가할 함수만 따로 작성합니다.

 1// 업데이트가 필요한지 확인하는 bool 변수 생성
 2bool isNeedUpdateScreen = true;
 3
 4void updateMaterial(int index)
 5{
 6    // isNeedUpdate 변수가 false 이면 함수를 종료함
 7    if(!isNeedUpdateScreen) return;
 8
 9    // 목표 온도, 속도 항목에 현재 인덱스의 구조체 값을 저장
10    setTemperature = materials[index].temperature;
11
12    // 화면 클리어
13    ssd1306_clearScreen();
14
15    // 화면에 목표 온도, 재료 명, 속도를 표시
16    // 재료명은 좌표 0,0 에 표시
17    // 목표 온도는 좌표 52, 16 에 표시
18    strToShow = materials[index].materialName;
19    showTextToScreen(0,0, strToShow);
20
21    strToShow = "/" + String(setTemperature);
22    showTextToScreen(52,16,strToShow);
23
24    // 화면을 계속해서 업데이트 하지 않도록 방지하는 bool 변수 변경
25    isNeedUpdateScreen = false;
26}

위 함수는 isNeedUpdate 변수가 true 일 때마다 화면의 문자들을 현재의 값으로 변경해줍니다.
materials 구조체에서 현재 index의 값을 목표 온도, 목표 속도 변수에 저장합니다.
isNeedUpdate 는 버튼을 누를 때마다 변경되게 해야합니다. 따라서 버튼을 누르면 isNeedUpdate 변수와 updateMaterial 함수의 index를 매개변수 로 전달될 변수를 변경해주어야 합니다.
C, D 버튼을 누를 때 마다 변경하도록 합니다.

 1// 버튼이 눌러져 있는지 확인하는 bool 변수 생성
 2bool isPressedC_BTN, isPressedD_BTN;
 3
 4void checkBtnPressed()
 5{
 6    // C버튼이 눌리고, D버튼이 눌리지 않았을 경우 실행
 7    if(!digitalRead(BTN_C) && digitalRead(BTN_D))
 8    {
 9        // C 버튼이 눌러져 있으면(isPressedC_BTN 가 true), 아래 코드 건너뜀
10        if(!isPressedC_BTN)
11        {
12            // 구조체 배열의 인덱스로 사용될 변수 값 1 증가
13            material_index++;
14            if(material_index > MATERIAL_COUNT-1)
15            {
16                material_index = 0;
17            }
18
19            // 디스플레이 업데이트를 할 수 있도록 변수 변경
20            isNeedUpdateScreen = true;
21        }
22    }
23    // D버튼이 눌리고, C버튼이 눌리지 않았을 경우 실행
24    else if(digitalRead(BTN_C) && !digitalRead(BTN_D))
25    {
26        // D 버튼이 눌러져 있으면(isPressedD_BTN 가 true), 아래 코드 건너뜀
27        if(!isPressedD_BTN)
28        {
29            // 구조체 배열의 인덱스로 사용될 변수 값 1 감소
30            material_index--;
31            if(material_index < 0)
32            {
33                material_index = MATERIAL_COUNT-1;
34            }
35
36            // 디스플레이 업데이트를 할 수 있도록 변수 변경
37            isNeedUpdateScreen = true;
38        }
39    }
40    else
41    {
42        // C, D 버튼 모두 눌리지 않을 경우, 변수 값 변경
43        isPressedC_BTN = false;
44        isPressedD_BTN = false;
45    }
46
47}

버튼이 눌러졌는지 체크하는 함수를 작성하였습니다. 추후 A,B 버튼에 대한 코드도 작성이 되겠지만, 이번 단계에서는 C,D 버튼에 해당되는 코드만 작성하였습니다.
버튼이 눌러져 있는 경우에도 계속해서 코드가 실행되면 안되니, bool 변수를 추가하였습니다.
또한 구조체의 배열 인덱스를 증감시키고, isNeedUpdateScreen 변수의 값을 변경시켜, loop의 코드가 반복수행 하면서 디스플레이를 업데이트 시킵니다.

그렇다면, 코드를 합치고, 이번 단계에서의 최종 코드를 작성해보겠습니다.
  1#include "ssd1306.h" // 라이브러리 포함
  2
  3#define BTN_A           8      // A버튼
  4#define BTN_B           7      // B버튼
  5#define BTN_C           11     // C버튼
  6#define BTN_D           12     // D버튼
  7
  8#define MOTOR_EN        5      // 모터 활성화 핀
  9#define MOTOR_DIR       6      // 모터 방향 핀
 10#define MOTOR_SPEED     10     // 모터 속도 핀
 11
 12#define HEATER_EN       9      // 열선 핀
 13
 14#define TEMP_IN         A0     // 온도 읽는 핀
 15
 16#define VALUE_TEMPTB    0      // 온도 테이블의 신호 값 인덱스
 17#define CELSIUS_TEMPTB  1      // 온도 테이블의 온도 값 인덱스
 18
 19#define MATERIAL_COUNT  3      // material 구조체 배열의 갯수
 20
 21String strToShow;              // 디스플레이에 보여줄 문자열을 저장하는 변수
 22
 23bool isNeedUpdateScreen = true;      // 업데이트가 필요한지 확인하는 bool 변수 생성
 24bool isPressedC_BTN, isPressedD_BTN; // 버튼이 눌러져 있는지 확인하는 bool 변수 생성
 25
 26int curTemp = 0; // 현재온도
 27
 28long timeInterval  = millis(); // 50ms 에 1회씩 작동하기 위한 시간 변수
 29
 30int material_index = 0;        // 재료 구조체 배열의 위치를 가리키는 인덱스
 31int setTemperature = 0;        // 설정된 온도
 32
 33// 온도, 속도, 재료명을 포함한 구조체 선언
 34struct setting {
 35    int temperature;
 36    char* materialName;
 37};
 38
 39struct setting materials[] = {{0, "OFF"}, {60, "PCL"}, {200,"PLA"}};
 40
 41/*
 42 *  온도 테이블 배열
 43 *  첫번째 항목은 신호 값, 두번째 항목은 온도 값
 44 */
 45int temptable[23][2] = {
 46    {1023,0},
 47    {1022,10},
 48    {1020,20},
 49    {1016,30},
 50    {1011,40},
 51    {1009,50},
 52    {1006,60},
 53    {1004,70},
 54    {1000,80},
 55    {990,90},
 56    {983,100},
 57    {976,110},
 58    {972,120},
 59    {964,130},
 60    {955,140},
 61    {942,150},
 62    {929,160},
 63    {910,170},
 64    {895,180},
 65    {864,190},
 66    {839,200},
 67    {800,210},
 68    {744,220}
 69};
 70
 71/*
 72 * 입력받은 문자를 디스플레이 좌표에 표시
 73 */
 74void showTextToScreen(int x, int y, String text)
 75{
 76    text = text + "\n";
 77    char ch[10];
 78    text.toCharArray(ch,text.length());
 79    ssd1306_printFixedN(x, y, ch, STYLE_NORMAL, FONT_SIZE_2X);
 80}
 81
 82/*
 83 * 온도를 읽고, 정확한 온도로 계산 후 결과 값을 화면에 표시하고 반환하는 함수
 84 * VALUE_TEMPTB = 0, CELSIUS_TEMPTB = 1 으로 온도표의 각 항목을 지시함
 85 */
 86int getTemperature()
 87{
 88    float ratioTemp;
 89    float tempADU = analogRead(A0);
 90    int result;
 91
 92    for(int i=1; i<23; i++){
 93        if(tempADU >= temptable[i][VALUE_TEMPTB])
 94        {
 95            ratioTemp = (tempADU - temptable[i][VALUE_TEMPTB])/(temptable[i-1][VALUE_TEMPTB] - temptable[i][VALUE_TEMPTB]);
 96
 97            result = temptable[i][CELSIUS_TEMPTB] - ratioTemp*(temptable[i][CELSIUS_TEMPTB] - temptable[i-1][CELSIUS_TEMPTB]);
 98
 99            strToShow = String(result);
100
101            showTextToScreen(0,16,strToShow);
102
103            return result;
104        }
105    }
106
107    return ;
108}
109
110/*
111 * 버튼이 눌러졌는지 확인하고, 해당버튼에 맞는 코드 실행
112 */
113void checkBtnPressed()
114{
115    // C버튼이 눌리고, D버튼이 눌리지 않았을 경우 실행
116    if(!digitalRead(BTN_C) && digitalRead(BTN_D))
117    {
118        // C 버튼이 눌러져 있으면(isPressedC_BTN 가 true), 아래 코드 건너뜀
119        if(!isPressedC_BTN)
120        {
121            // 구조체 배열의 인덱스로 사용될 변수 값 1 증가
122            material_index++;
123            if(material_index > MATERIAL_COUNT-1)
124            {
125                material_index = 0;
126            }
127
128            // 디스플레이 업데이트를 할 수 있도록 변수 변경
129            isNeedUpdateScreen = true;
130
131            // 버튼 상태 변수 변경
132            isPressedC_BTN = true;
133        }
134    }
135    // D버튼이 눌리고, C버튼이 눌리지 않았을 경우 실행
136    else if(digitalRead(BTN_C) && !digitalRead(BTN_D))
137    {
138        // D 버튼이 눌러져 있으면(isPressedD_BTN 가 true), 아래 코드 건너뜀
139        if(!isPressedD_BTN)
140        {
141            // 구조체 배열의 인덱스로 사용될 변수 값 1 감소
142            material_index--;
143            if(material_index < 0)
144            {
145                material_index = MATERIAL_COUNT-1;
146            }
147
148            // 디스플레이 업데이트를 할 수 있도록 변수 변경
149            isNeedUpdateScreen = true;
150
151            // 버튼 상태 변수 변경
152            isPressedD_BTN = true;
153        }
154    }
155    else
156    {
157        // C, D 버튼 모두 눌리지 않을 경우, 변수 값 변경
158        isPressedC_BTN = false;
159        isPressedD_BTN = false;
160    }
161
162}
163
164/*
165 * 화면에 표시될 재료명, 목표속도, 목표온도를 업데이트
166 */
167void updateMaterial(int index)
168{
169    // isNeedUpdate 변수가 false 이면 함수를 종료함
170    if(!isNeedUpdateScreen) return;
171
172    // 목표 온도, 속도 항목에 현재 인덱스의 구조체 값을 저장
173    setTemperature = materials[index].temperature;
174    setMotorSpeed  = materials[index].motorSpeed;
175
176    // 화면 클리어
177    ssd1306_clearScreen();
178
179    // 화면에 목표 온도, 재료 명, 속도를 표시
180    // 재료명은 좌표 0,0 에 표시
181    // 목표 온도는 좌표 52, 16 에 표시
182    strToShow = materials[index].materialName;
183    showTextToScreen(0,0, strToShow);
184
185    strToShow = "/" + String(setTemperature);
186    showTextToScreen(52,16,strToShow);
187
188    // 화면을 계속해서 업데이트 하지 않도록 방지하는 bool 변수 변경
189    isNeedUpdateScreen = false;
190}
191
192void setup()
193{
194    pinMode(BTN_A, INPUT_PULLUP);
195    pinMode(BTN_B, INPUT_PULLUP);
196    pinMode(BTN_C, INPUT_PULLUP);
197    pinMode(BTN_D, INPUT_PULLUP);
198
199    pinMode(MOTOR_EN, OUTPUT);
200    pinMode(MOTOR_DIR, OUTPUT);
201    pinMode(MOTOR_SPEED, OUTPUT);
202
203    pinMode(HEATER_EN, OUTPUT);
204
205    digitalWrite(MOTOR_EN, HIGH); // 모터 활성화
206
207    ssd1306_128x32_i2c_init(); // 32로 변경
208    ssd1306_fillScreen(0x00);  // 화면 초기화
209    ssd1306_setFixedFont(ssd1306xled_font6x8); // 폰트 설정
210    ssd1306_flipHorizontal(1); // x 화면 대칭 회전
211    ssd1306_flipVertical(1);   // y 화면 대칭 회전
212}
213
214void loop()
215{
216    if(millis() - timeInterval > 50)
217    {
218        curTemp = getTemperature();
219        updateMaterial(material_index);
220        checkBtnPressed();
221
222        timeInterval = millis();
223    }
224}