--- title: 北農程式實習 lang: zh_TW description: 北農程式實習 --- [![hackmd-github-sync-badge](https://hackmd.io/FW2ksRR5Rneynl3fHieuIg/badge)](https://hackmd.io/FW2ksRR5Rneynl3fHieuIg) :::info 最後修訂: 2024/05/13 ::: --- [toc] <details> <summary>相關連結</summary> - [Github](https://github.com/a3510377) </details> # STM32 > 可能有部分程式有問題或不完整,請告知 [猴子 (*Gmail*)](mailto:a102009102009@gmail.com) > [name=猴子] ## 第一章 ### 兩顆 LED 輪流閃爍 0.5s <details> <summary>展開程式</summary> ```cpp= while (1) { for (uint8_t i = 0; i <= 1; i++) { HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_SET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOC, 1 << i, GPIO_PIN_RESET); } } ``` ```cpp= while (1) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); } ``` </details> ### 16 顆 LED 霹靂燈,左右旋 0.2s <details> <summary>展開程式</summary> ```cpp= # define abs(x) ((x) > 0 ? (x) : -(x)) while (1) { for (int8_t i = -15; i < 15; i++) { GPIOC->ODR = 1 << abs(i); HAL_Delay(200); } } ``` </details> <!-- // Use BSRR to prevent interrupts GPIOC->BSRR = (~pin << 16) | pin; --> ### 8 顆 LED 漸增在漸減 - 建表法,左右旋 0.2s <details> <summary>展開程式</summary> ```cpp= const uint8_t LED[] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03}; const uint8_t LED_LEN = sizeof(LED) / sizeof(uint8_t); while (1) { for (uint8_t i = 0; i < LED_LEN; i++) { GPIOC->ODR = LED[i]; HAL_Delay(200); } } ``` </details> ### 左右旋 - 建表法 & 中斷 <details> <summary>展開程式</summary> ```cpp= #define USE_BSRR const uint8_t LED[] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03}; int timercnt, step; HAL_TIM_Base_Start_IT(&htim6); while (1) { if (!timercnt) { timercnt = 300; step = (step + 1) % 14; } GPIOC->ODR = LED[step]; } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (timercnt > 0) timercnt--; } ``` </details> ### 8顆 LED速度變快 <details> <summary>展開程式</summary> ```cpp= const uint8_t LED[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; int timercnt, step, time_step; HAL_TIM_Base_Start_IT(&htim6); while (1) { if (timercnt == 0) { if (++step > 7) { step = 0; if (++time_step > 7) time_step = 0; } timercnt = (time_step + 1) * 100; } GPIOC->ODR = LED[step]; } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (timercnt > 0) timercnt--; } ``` </details> ## 第二章 ### 兩顆按鈕搭配 LED 燈做上下數 <details> <summary>展開程式</summary> ```cpp= #define PC GPIOC->ODR #define CHECK_BTN(pin) (!HAL_GPIO_ReadPin(GPIOB, pin) && flag & pin) int value, last_flag; while(1) { if (CHECK_BTN(GPIO_PIN_0)) { value = (value + 1) % 16; } else if (CHECK_BTN(GPIO_PIN_1)) { value = !value ? 15 : value - 1; } PC = value; last_flag = GPIOB->IDR; HAL_Delay(2); } ``` ```cpp== #define CHECK_BTN(pin) (!HAL_GPIO_ReadPin(GPIOB, pin) && flag & pin) const uint8_t LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; unsigned int last_time; int value; char flag; // ----- unsigned int now = HAL_GetTick(); if (last_time + 200 < now) { if (reverse) value = value > 0 ? value - 1 : 9; else value = (value + 1) % 9; last_time = now; } if (CHECK_BTN(GPIO_PIN_0)) reverse = 1; else if (CHECK_BTN(GPIO_PIN_1)) reverse = 0; flag = GPIOB->IDR; PC = ~LED[value]; HAL_Delay(20); ``` </details> ### 請設計四位數搭配三顆按鈕第一顆按鈕做上數,第二顆按鈕做下數第三顆做暫停第四顆做歸零 <details> <summary>展開程式</summary> ```cpp= #define PC GPIOC->ODR #define SELECT_DISPLAY(i) ((~(1 << i) & 0xf) << 8) #define CHECK_BTN(pin) (!HAL_GPIO_ReadPin(GPIOB, pin) && flag & pin) char flag, value, reverse; unsigned int time1; const uint8_t LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; uint32_t displays_value[4], show_index; unsigned int time2; void display() { uint16_t tmp = value; for (int i = 0; i <= 3; i++) { displays_value[i] = LED[tmp % 10] | SELECT_DISPLAY(i); tmp /= 10; } GPIOC->ODR = ~displays_value[show_index]; } // ----- unsigned int now = HAL_GetTick(); if (time1 + 200 <= now) { if (reverse == 1) value = value > 0 ? value - 1 : 9999; else if (reverse == 2) value = (value + 1) % 10000; time1 = now; } if (time2 + 4 <= now) { show_index = (show_index + 1) % 4; time2 = now; if (CHECK_BTN(GPIO_PIN_1)) reverse = 0; else if (CHECK_BTN(GPIO_PIN_3)) reverse = 1; else if (CHECK_BTN(GPIO_PIN_0)) reverse = 2; else if (CHECK_BTN(GPIO_PIN_2)) { value = 0; reverse = 0; } } flag = GPIOB->IDR; display(); ``` </details> ## 第三章 PWM 不同頻率 與 ADC 設定 ### 在頻率 1kHz 下 <details> <summary>展開程式</summary> ```cpp= #define SELECT_DISPLAY(i) ((~(1 << i) & 0xf) << 8) int adc_value; const uint8_t LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; int LIGHT_MAP[4] = {0, 15, 50, 100}; int index; unsigned int time; void read_adc() { HAL_ADC_Start(&hadc); HAL_ADC_PollForConversion(&hadc, 1); HAL_ADC_Stop(&hadc); } while(true) { read_adc(); adc1_value = HAL_ADC_GetValue(&hadc) * 100 / 1023; TIM2->CCR1 = LIGHT_MAP[(int) (adc1_value / 25)]; unsigned int now = HAL_GetTick(); if (time + 4 <= now) { index = (index + 1) % 3; time = now; } int value = 1; for (int i = 0; i < index; i++) value *= 10; int tmp = adc1_value / value; GPIOC->ODR = ~(LED[tmp % 10] | SELECT_DISPLAY(index)); } ``` </details> ### 四位數7段顯示器 <details> <summary>展開程式</summary> ```cpp= #define SELECT_DISPLAY(i) ((~(1 << i) & 0xf) << 8) const uint8_t LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; unsigned int time; int show_value, show_index; while(true) { show_value = 255; int tmp = show_value; for (int i = 0; i < 4; i++) { P2 = LED[tmp % 10]; delay(3); P2 = 0xff; tmp /= 10; } } ``` ```cpp= #define SELECT_DISPLAY(i) ((~(1 << i) & 0xf) << 8) const uint8_t LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; unsigned int time; int show_value, show_index; while(true) { show_value = 255; unsigned int now_time = HAL_GetTick(); if (time + 4 <= now_time) { show_index = (show_index + 1) % 4; time = now_time; } int value = 1; for (int i = 0; i < show_index; i++) value *= 10; int tmp = show_value / value; GPIOC->ODR = ~(LED[tmp % 10] | SELECT_DISPLAY(show_index)); } ``` ```cpp= #define SELECT_DISPLAY(i) ((~(1 << (i)) & 0xf) << 8) #define CHECK_BTN(pin) (!HAL_GPIO_ReadPin(GPIOB, pin) && btn_flag & pin) const uint8_t LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; const uint16_t TONE_TAB[] = {0, 1912, 1704, 1518, 1432, 1276, 1136, 1012}; unsigned int time; int show_value, show_index, tone_index; char btn_flag; void tone(int index) { TIM2->ARR = TONE_TAB[index]; TIM2->CCR1 = TONE_TAB[index] / 2; } while (1) { unsigned int now_time = HAL_GetTick(); if (time + 4 <= now_time) { show_index = (show_index + 1) % 4; time = now_time; if (CHECK_BTN(GPIO_PIN_0)) { tone_index = (tone_index + 1) % 8; } else if (CHECK_BTN(GPIO_PIN_1) && tone_index > 0) { tone_index--; } else if (CHECK_BTN(GPIO_PIN_2)) { tone_index = 0; } btn_flag = GPIOB->IDR; } // if (GPIOB->IDR) // if (time1 + 1000 <= now_time) { // tone_index = (tone_index + 1) % 8; // time1 = now_time; // } tone(tone_index); show_value = TONE_TAB[tone_index] / 2; int value = 1; for (int i = 0; i < show_index; i++) value *= 10; int tmp = show_value / value; GPIOC->ODR = (LED[tmp % 10] | SELECT_DISPLAY(show_index)); } ``` </details> ## Other ### UART <details> <summary>展開程式</summary> ```cpp= #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define UART_TX_BUFFER_SIZE 256 void UART_Transmit(const char *format, ...) { char buffer[UART_TX_BUFFER_SIZE]; va_list args; va_start(args, format); int len = vsnprintf(buffer, UART_TX_BUFFER_SIZE, format, args); va_end(args); if (len < 0) return; else if (len >= UART_TX_BUFFER_SIZE) { char *dyn_buffer = (char *)malloc(len + 1); if (dyn_buffer == NULL) return; va_start(args, format); vsnprintf(dyn_buffer, len + 1, format, args); va_end(args); HAL_UART_Transmit(&huart2, (uint8_t *)dyn_buffer, len, 200); free(dyn_buffer); } else { HAL_UART_Transmit(&huart2, (uint8_t *)buffer, len, 200); } } ``` </details> ### Utils <details> <summary>展開程式</summary> ```c= #ifndef __MK_LIB_H__ #define __MK_LIB_H__ #include "stm32l0xx_hal.h" #ifdef __cplusplus #include <algorithm> using std::max; using std::min; #else /* __cplusplus */ #include <stdlib.h> #ifndef abs #define abs(x) ((x) > 0 ? (x) : -(x)) #endif /* abs */ #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif /* min */ #ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) #endif /* max */ #endif /* __cplusplus */ void delayMicroseconds(uint32_t us); uint32_t micros(void); inline uint32_t millis(void) { return HAL_GetTick(); } uint32_t pulseIn(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint32_t state, uint32_t timeout); #endif /* __MK_LIB_H__ */ ``` ```cpp= void delayMicroseconds(uint32_t us) { if (us == 0) return; const uint32_t start = SysTick->VAL; const uint32_t tickPerMs = SysTick->LOAD + 1; const uint32_t ticks = ((us - 1) * tickPerMs) / 1e3; while (start - SysTick->VAL < ticks); } uint32_t micros(void) { uint32_t m0 = HAL_GetTick(); __IO uint32_t u0 = SysTick->VAL; uint32_t m1 = HAL_GetTick(); __IO uint32_t u1 = SysTick->VAL; const uint32_t tickPerMs = SysTick->LOAD + 1; return m1 != m0 ? m1 * 1e3 + ((tickPerMs - u1) * 1e3) / tickPerMs : m0 * 1e3 + ((tickPerMs - u0) * 1e3) / tickPerMs; } uint32_t pulseIn(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint32_t state, uint32_t timeout) { uint32_t startMicros = micros(); uint16_t stateMask = state ? GPIO_Pin : 0; // wait for any previous pulse to end while ((GPIOx->IDR & GPIO_Pin) == stateMask) { if (micros() - startMicros > timeout) { return 0; } } // wait for the pulse to start while ((GPIOx->IDR & GPIO_Pin) != stateMask) { if (micros() - startMicros > timeout) { return 0; } } uint32_t start = micros(); // wait for the pulse to stop while ((GPIOx->IDR & GPIO_Pin) == stateMask) { if (micros() - startMicros > timeout) { return 0; } } return micros() - start; } ``` </details> # 89S52 ## 四位數七段顯示器 <details> <summary>展開程式</summary> ```cpp== #include <regx51.h> const unsigned char LED[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x6f}; unsigned int show_value; unsigned char show_index, j; void delay(unsigned int ms); void display(void); void main() { for (show_value = 0; show_value < 10000; show_value++) { for (j = 0; j < 20; j++) { for (show_index = 0; show_index < 4; show_index++) { display(); delay(3); P2 = 0xff; } } } } void delay(unsigned int ms) { unsigned int j; unsigned char k; for(j=0; j < ms; j++) for(k = 0; k < 120; k++); } void display() { unsigned char i; unsigned int tmp = show_value; for (i = 0; i < show_index; i++) tmp /= 10; P2 = ~LED[tmp % 10]; P3 = ~(1 << show_index); } ``` </details> --- <!-- {%hackmd Wd1xvc_AQuSzWZPcQXSn3Q %} --> <!-- #define CHECK_BTN(pin) (!HAL_GPIO_ReadPin(GPIOB, pin) && last_flag & pin) uint8_t music_index, play_index, has_next_buf; uint32_t last_flag, last_time; #define TONE(s) (s) const uint16_t TONE_TABLE[] = {0, 1912, 1704, 1518, 1432, 1276, 1136, 1012}; const uint16_t MUSIC_INDEX[] = {0, 52}; const uint8_t MUSIC_SIZE = sizeof(MUSIC_INDEX) / sizeof(uint16_t); const uint16_t MUSICS[] = { /* music-1 */ TONE(1), 4, TONE(1), 4, TONE(2), 8, TONE(1), 8, TONE(4), 8, TONE(3), 16, TONE(1), 4, TONE(1), 4, TONE(2), 8, TONE(1), 8, TONE(5), 8, TONE(4), 16, TONE(1), 4, TONE(1), 4, TONE(8), 8, TONE(6), 8, TONE(4), 8, TONE(3), 8, TONE(2), 8, TONE(11), 4, TONE(11), 4, TONE(6), 8, TONE(4), 8, TONE(5), 8, TONE(4), 16, 100, 100, /* music-2 */ TONE(1), 4, TONE(1), 4, TONE(2), 8, TONE(1), 8, TONE(4), 8, 100, 100, // END }; void tone(int index) { TIM2->ARR = TONE_TABLE[index]; TIM2->CCR1 = TONE_TABLE[index] / 2; } HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); if (last_time > HAL_GetTick()) { HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); HAL_Delay(5); play_index += 2; if (MUSICS[play_index] == 100) { // reset play_index = MUSIC_INDEX[music_index]; } has_next_buf = 0; } else if (!has_next_buf) { has_next_buf = 1; tone(MUSICS[play_index]); char buf[25]; sprintf(buf, "tone: %03d", MUSICS[play_index]); UART_SendString((uint8_t *)buf); sprintf(buf, "; delay: %02d\r\n", MUSICS[play_index + 1]); UART_SendString((uint8_t *)buf); last_time = HAL_GetTick() + MUSICS[play_index + 1] * 110; HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); } if (CHECK_BTN(GPIO_PIN_0)) { // next button music_index = (music_index + 1) % MUSIC_SIZE; play_index = MUSIC_INDEX[music_index]; } else if (CHECK_BTN(GPIO_PIN_1)) { // prev button music_index = !music_index ? MUSIC_SIZE : MUSIC_SIZE - 1; play_index = MUSIC_INDEX[music_index]; } last_flag = GPIOB->IDR; HAL_TIM_PWM_Start(&htim21, TIM_CHANNEL_2); HAL_TIM_Base_Start_IT(&htim6); Initialize_LCD(hi2c1); clear_LCD(); int status = 0; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { char str[255]; sprintf(str, "Distance : %03d", distance > 99 ? 99 : distance); writes(0x80, str); if (status == 7) { sprintf(str, "NO : 11 %s", "Safe"); } else if (status >= 2){ sprintf(str, "NO : 11 %s", "Stop"); } else { sprintf(str, "NO : 11 %s", " "); } writes(0xC0, str); if (distance < 30) { if (!timecent2) { if (distance < 10) { timecent2 = 400; } else if (distance < 20) { timecent2 = 800; } else { timecent2 = 1200; } status = (status + 1) % 6; } if (status % 2) { TIM21->ARR = 1912; TIM21->CCR2 = 956; } else { TIM21->ARR = 0; TIM21->CCR2 = 0; } } else { TIM21->ARR = 0; TIM21->CCR2 = 0; status = 7; } if (timecent == 0) { timecent = 800; trigger(); while (!PB2_R); __HAL_TIM_SET_COUNTER(&htim2, 0); HAL_TIM_Base_Start(&htim2); while (PB2_R); HAL_TIM_Base_Stop(&htim2); distance = __HAL_TIM_GetCounter(&htim2) / 58; distance = distance > 99 ? 99 : distance; } --> <!-- #include <regx51.h> unsigned char mode, old_mode, old, tmp2, tmp3; unsigned int tmp1; void delay(unsigned int ms); void main() { while (1) { // unsigned char tmp = !P3_2; // if (tmp && tmp != old) { // mode = (mode + 1) % 6; // } // old = tmp; mode = (~P0 & 0x07) % 6; if (mode != old_mode) { tmp1 = tmp2 = 0x00; old_mode = mode; tmp3 = 1; } if (!tmp1) { switch (mode) { case 0: { tmp2 = 0x00; } break; case 1: { tmp2 = 0xff; } break; case 2: { tmp2 = tmp3 ? 0xff : 0x00; tmp3 = !tmp3; } break; case 3: { tmp2 <<= 1; if (!tmp2) tmp2 = 0x01; } break; case 4: { tmp2 >>= 1; if (!tmp2) tmp2 = 0x80; } break; case 5: { tmp2 = tmp3 ? tmp2 << 1 : tmp2 >> 1; if (!tmp2) { tmp3 = !tmp3; tmp2 = tmp3 ? 0x02 : 0x40; } } break; } } P1 = ~tmp2; if (tmp1 > 0) tmp1--; else tmp1 = 500; delay(1); } } void delay(unsigned int ms) { unsigned int j; unsigned char k; for(j=0; j < ms; j++) for(k = 0; k < 120; k++); } -->