การเขียนโปรแกรม STM32F4 การสร้างโครงการใหม่ใน Keil STM32F407(STM32F4-DISCOVERY) - วิธีการที่ไม่ได้มาตรฐาน - ไลบรารี่มาตรฐานตอนที่ 1
จนถึงจุดนี้ เราได้ใช้ไลบรารีเคอร์เนลมาตรฐาน - CMSIS ในการกำหนดค่าพอร์ตให้เป็นโหมดการทำงานที่ต้องการ เราต้องค้นหารีจิสเตอร์ที่รับผิดชอบฟังก์ชันบางอย่าง และค้นหาข้อมูลอื่นๆ ที่เกี่ยวข้องกับกระบวนการนี้ในเอกสารขนาดใหญ่ด้วย สิ่งต่างๆ จะเจ็บปวดและเป็นกิจวัตรมากขึ้นเมื่อเราเริ่มทำงานโดยใช้เครื่องจับเวลาหรือ ADC จำนวนรีจิสเตอร์มีมากกว่าพอร์ต I/O มาก การกำหนดค่าด้วยตนเองใช้เวลานานและเพิ่มโอกาสที่จะเกิดข้อผิดพลาด ดังนั้นหลายคนจึงชอบทำงานกับไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน - StdPeriph มันให้อะไร? ง่ายมาก - ระดับของนามธรรมจะเพิ่มขึ้น คุณไม่จำเป็นต้องเข้าไปดูเอกสารประกอบและคิดถึงการลงทะเบียนเป็นส่วนใหญ่ ในไลบรารีนี้ โหมดการทำงานและพารามิเตอร์ทั้งหมดของขอบ MK ได้รับการอธิบายไว้ในรูปแบบของโครงสร้าง ตอนนี้ ในการกำหนดค่าอุปกรณ์ต่อพ่วง คุณจะต้องเรียกใช้ฟังก์ชันการเริ่มต้นอุปกรณ์ด้วยโครงสร้างที่เติมเต็มเท่านั้น
ด้านล่างนี้เป็นรูปภาพที่มีการแสดงแผนผังของระดับของสิ่งที่เป็นนามธรรม
เราทำงานร่วมกับ CMSIS (ซึ่ง "ใกล้เคียงที่สุด" กับแกนกลาง) เพื่อแสดงให้เห็นว่าไมโครคอนโทรลเลอร์ทำงานอย่างไร ขั้นตอนต่อไปคือไลบรารีมาตรฐาน ซึ่งเราจะเรียนรู้วิธีใช้งานทันที ถัดมาเป็นไดรเวอร์อุปกรณ์ เข้าใจว่าเป็นไฟล์ *.c \ *.h ที่มีอินเทอร์เฟซซอฟต์แวร์ที่สะดวกสำหรับการควบคุมอุปกรณ์ใด ๆ ตัวอย่างเช่น ในหลักสูตรนี้ เราจะจัดเตรียมไดรเวอร์สำหรับชิป max7219 และโมดูล esp8266 WiFi ให้กับคุณ
โครงการมาตรฐานจะรวมไฟล์ต่อไปนี้:
![](https://i0.wp.com/66.media.tumblr.com/3e7f15dfcd52555c25b4d7af99c034f7/tumblr_inline_occxcrxjf41t55lnu_500.png)
ก่อนอื่นแน่นอนว่าไฟล์เหล่านี้เป็นไฟล์ CMSIS ที่อนุญาตให้ไลบรารีมาตรฐานทำงานกับเคอร์เนลเราได้พูดคุยกันแล้ว ประการที่สอง ไฟล์ไลบรารีมาตรฐาน และประการที่สาม ไฟล์ผู้ใช้
ไฟล์ไลบรารีสามารถพบได้บนหน้าที่ทุ่มเทให้กับ MK เป้าหมาย (สำหรับเราคือ stm32f10x4) ในส่วน ทรัพยากรการออกแบบ(ใน CooCox IDE ไฟล์เหล่านี้จะถูกดาวน์โหลดจากพื้นที่เก็บข้อมูลสภาพแวดล้อมการพัฒนา) อุปกรณ์ต่อพ่วงแต่ละอันสอดคล้องกับสองไฟล์ - ส่วนหัว (*.h) และซอร์สโค้ด (*.c) คำอธิบายโดยละเอียดสามารถพบได้ในไฟล์สนับสนุนซึ่งอยู่ในไฟล์เก็บถาวรพร้อมไลบรารีบนเว็บไซต์
- stm32f10x_conf.h - ไฟล์กำหนดค่าไลบรารี ผู้ใช้สามารถเชื่อมต่อหรือยกเลิกการเชื่อมต่อโมดูลได้
- stm32f10x_ppp.h - ไฟล์ส่วนหัวต่อพ่วง แทนที่จะเป็น ppp อาจเป็น gpio หรือ adc
- stm32f10x_ppp.c - ไดรเวอร์อุปกรณ์ต่อพ่วงที่เขียนด้วยภาษา C
- stm32f10x_it.h - ไฟล์ส่วนหัวที่มีตัวจัดการการขัดจังหวะที่เป็นไปได้ทั้งหมด (ต้นแบบ)
- stm32f10x_it.c เป็นไฟล์ซอร์สโค้ดเทมเพลตที่มี Interrupt Service Routine (ISR) สำหรับสถานการณ์ข้อยกเว้นใน Cortex M3 ผู้ใช้สามารถเพิ่ม ISR ของตนเองสำหรับอุปกรณ์ต่อพ่วงที่ใช้ได้
ไลบรารีมาตรฐานและอุปกรณ์ต่อพ่วงมีหลักการในการตั้งชื่อฟังก์ชันและสัญลักษณ์
- PPP เป็นตัวย่อสำหรับอุปกรณ์ต่อพ่วง เช่น ADC
- ไฟล์ระบบ ส่วนหัว และซอร์สโค้ด - เริ่มต้นด้วย stm32f10x_
- ค่าคงที่ที่ใช้ในไฟล์เดียวถูกกำหนดไว้ในไฟล์นั้น ค่าคงที่ที่ใช้ในไฟล์มากกว่าหนึ่งไฟล์ถูกกำหนดไว้ในไฟล์ส่วนหัว ค่าคงที่ทั้งหมดในไลบรารีอุปกรณ์ต่อพ่วงมักเขียนด้วยตัวพิมพ์ใหญ่
- รีจิสเตอร์จะถือเป็นค่าคงที่และเรียกอีกอย่างว่าอักษรตัวพิมพ์ใหญ่
- ชื่อฟังก์ชันเฉพาะอุปกรณ์ต่อพ่วงจะมีตัวย่อ เช่น USART_SendData()
- ในการกำหนดค่าอุปกรณ์ต่อพ่วงแต่ละชิ้น จะใช้โครงสร้าง PPP_InitTypeDef ซึ่งถูกส่งผ่านไปยังฟังก์ชัน PPP_Init()
- หากต้องการยกเลิกการกำหนดค่าเริ่มต้น (ตั้งค่าเป็นค่าเริ่มต้น) คุณสามารถใช้ฟังก์ชัน PPP_DeInit() ได้
- ฟังก์ชันที่อนุญาตให้คุณเปิดหรือปิดใช้งานอุปกรณ์ต่อพ่วงเรียกว่า PPP_Cmd()
- ฟังก์ชันเปิด/ปิดใช้งานการขัดจังหวะเรียกว่า PPP_ITConfig
คุณสามารถดูรายการทั้งหมดได้ในไฟล์สนับสนุนห้องสมุดอีกครั้ง ตอนนี้เรามาเขียน LED ที่กะพริบใหม่โดยใช้ไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน!
ก่อนเริ่มงานเรามาดูไฟล์ stm32f10x.h และค้นหาบรรทัด:
#กำหนด USE_STDPERIPH_DRIVER
หากคุณกำหนดค่าโปรเจ็กต์ตั้งแต่เริ่มต้นโดยใช้ไฟล์ไลบรารีจากไฟล์เก็บถาวรที่ดาวน์โหลด คุณจะต้องยกเลิกการแสดงความคิดเห็นในบรรทัดนี้ มันจะช่วยให้คุณใช้ไลบรารี่มาตรฐานได้ คำจำกัดความนี้ (มาโคร) จะสั่งให้ตัวประมวลผลล่วงหน้ารวมไฟล์ stm32f10x_conf.h:
#ifdef USE_STDPERIPH_DRIVER #รวม "stm32f10x_conf.h" #endif
ไฟล์นี้มีโมดูล หากคุณต้องการเฉพาะอันที่เจาะจง ให้ปิดการใช้งานส่วนที่เหลือ ซึ่งจะช่วยประหยัดเวลาในระหว่างการคอมไพล์ ตามที่คุณอาจเดาได้เราต้องการโมดูล RTC และ GPIO (อย่างไรก็ตามในอนาคตเราจะต้องมี _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h):
#include "stm32f10x_flash.h" // สำหรับ init_pll() #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h"
เช่นเดียวกับครั้งก่อน คุณต้องเปิดใช้งานการตอกบัตรของพอร์ต B ก่อน ซึ่งทำได้โดยฟังก์ชันที่ประกาศใน stm32f10x_rcc.h:
โมฆะ RCC_APB2PeriphClockCmd (uint32_t RCC_APB2Periph, FunctionalState NewState);
FunctionalState enum ถูกกำหนดไว้ใน stm32f10x.h:
Typedef enum (DISABLE = 0, ENABLE = !DISABLE) FunctionalState;
มาประกาศโครงสร้างสำหรับการตั้งค่าขาของเรา (คุณสามารถดูได้ในไฟล์ stm32f10x_gpio.h):
GPIO_InitTypeDef LED;
ตอนนี้เราต้องกรอกมัน ลองดูที่เนื้อหาของโครงสร้างนี้:
โครงสร้าง Typedef ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; ) GPIO_InitTypeDef;
การแจงนับและค่าคงที่ที่จำเป็นทั้งหมดสามารถพบได้ในไฟล์เดียวกัน จากนั้นฟังก์ชัน init_leds() ที่เขียนใหม่จะอยู่ในรูปแบบต่อไปนี้:
Void led_init() ( // เปิดใช้งานการตอกบัตร RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // ประกาศโครงสร้างและเติม GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GPIO_Speed = GPIO_Speed_2MHz; LED.GPIO_Mode = GPIO_Mode_ Out_PP; // เริ่มต้นพอร์ต GPIO_Init( GPIOB, &LED); )
มาเขียนฟังก์ชัน main() ใหม่กัน:
Int main(void) ( led_init(); ในขณะที่ (1) ( GPIO_SetBits(GPIOB, GPIO_Pin_0); ล่าช้า (10000000); GPIO_ResetBits(GPIOB, GPIO_Pin_0); ล่าช้า (10000000); ) )
สิ่งสำคัญคือการทำความเข้าใจลำดับการเริ่มต้น: เปิดนาฬิกาต่อพ่วง ประกาศโครงสร้าง เติมโครงสร้าง เรียกวิธีการเริ่มต้น อุปกรณ์ต่อพ่วงอื่นๆ มักจะได้รับการกำหนดค่าในลักษณะเดียวกัน
เป็นเวลานานมากแล้วที่บทความของเราไม่มีบทความใหม่ๆ เลย ถึงเวลาตามให้ทัน 😉 วันนี้เราจะมาเริ่มศึกษา STM32F4 กัน และอาจเริ่มต้นด้วยการสร้างโปรเจ็กต์ใหม่สำหรับคอนโทรลเลอร์เหล่านี้ แม้ว่าตามจริงแล้วฉันไม่ต้องการเขียนบทความเกี่ยวกับเรื่องนี้ เนื่องจากมีการสร้างโปรเจ็กต์ใหม่ที่นี่โดยหลักการแล้วในลักษณะเดียวกัน ส่วนรุ่น STM32F103 () แต่ก็ยังเกิดขึ้นที่ STM32F4 มีปัญหาบางอย่างเกิดขึ้น ดังนั้นเรามาพิจารณากระบวนการนี้โดยละเอียด)
เรามาเปิดตัว Keil สร้างโปรเจ็กต์ใหม่กันดีกว่า - โครงการ -> โครงการ uVision ใหม่เราบันทึกโปรเจ็กต์ใหม่ในบางโฟลเดอร์ จากนั้นเราจะถูกขอให้เลือกไมโครคอนโทรลเลอร์ที่จะใช้ ทีนี้มาเลือกกันให้เป็น STM32F407VG:
เสร็จสิ้นในกล่องโต้ตอบที่ปรากฏขึ้นให้คลิก "ใช่" จากนั้นไฟล์แรกจะถูกเพิ่มในโครงการของเรา - startup_stm32f4xx.s. เช่นเดียวกับเมื่อก่อนเราจะใช้ห้องสมุด ซีเอ็มซิสและ ไลบรารีอุปกรณ์ต่อพ่วงมาตรฐานแต่โดยธรรมชาติแล้วสำหรับคอนโทรลเลอร์ STM32F4xx แล้ว ดังนั้นเราจึงจำเป็นต้องดาวน์โหลดและเพิ่มไฟล์ที่จำเป็นลงในโปรเจ็กต์ที่ยังว่างเปล่าของเราอย่างแน่นอน อย่างไรก็ตาม ฉันได้ยินมาหลายครั้งแล้วจากหลายๆ คนว่าพวกเขาเจอห้องสมุดที่ "ไม่เป็นเช่นนั้น" สำหรับ F4 และแม้แต่โปรเจ็กต์ที่ง่ายที่สุดก็ยังไม่สามารถรวมเข้าด้วยกันได้ ตัวฉันเองไม่เคยเจอสิ่งนี้ แต่นี่คือไลบรารี่ที่ทดสอบแล้วที่ฉันเองใช้:
ดังนั้นเราจึงดาวน์โหลดมัน ทุกอย่างพร้อมแล้ว ตอนนี้เราเพิ่มไฟล์ลงในโปรเจ็กต์แล้ว รูปภาพแสดงสิ่งที่คุณต้องการ:
การเตรียมการเสร็จสมบูรณ์ ตอนนี้เรามาสร้างไฟล์ .c ใหม่ซึ่งจะมีโค้ดของเราอยู่ ไปกันเถอะ ไฟล์ -> ใหม่ไฟล์ว่างจะเปิดขึ้นใน Keil คลิก ไฟล์ -> บันทึกเป็นและบันทึกไว้ในชื่อ test.c เป็นต้น เมื่อบันทึกอย่าลืมระบุนามสกุลไฟล์ (.c) ไฟล์ถูกสร้างขึ้น เยี่ยมมาก แต่เราต้องเพิ่มมันลงในโปรเจ็กต์ของเราด้วย จริงๆ แล้ว ไม่มีอะไรซับซ้อนเกี่ยวกับเรื่องนี้ 😉 มาเขียนโปรแกรมทดสอบเปล่าลงในไฟล์นี้:
#รวม "stm32f4xx_rcc.h" #รวม "stm32f4xx_rcc.h" #รวม "stm32f4xx_gpio.h" /*******************************************************************/ int main() ( ในขณะที่ (1 ) ( __NOP() ; ) ) /*******************************************************************/ |
เกือบทุกอย่างพร้อมแล้ว สิ่งที่เหลืออยู่คือการดูการตั้งค่าโปรเจ็กต์ - โครงการ -> ตัวเลือกสำหรับเป้าหมาย...หน้าต่างจะเปิดขึ้นพร้อมกับแท็บต่างๆ มากมาย เราสนใจเพียงบางส่วนเท่านั้น เปิดแท็บ ซี/ซี++และในช่อง Define เราเขียนว่า:
ลงสนามแล้ว. คุณต้องเพิ่มเส้นทางไปยังไฟล์ทั้งหมดที่รวมอยู่ในโปรเจ็กต์ หลังจากเสร็จสิ้นขั้นตอนนี้ คุณสามารถกด F7 (สร้าง) และโปรเจ็กต์จะถูกสร้างขึ้นโดยไม่มีข้อผิดพลาดหรือคำเตือน อย่างที่คุณเห็นไม่มีอะไรซับซ้อน)
แต่โดยทั่วไปแล้ว โดยส่วนตัวแล้วฉันทำสิ่งที่แตกต่างออกไปเล็กน้อย ดูข้อเสียของวิธีนี้ ดังนั้นเราจึงดาวน์โหลดไลบรารี CMSIS และ SPL ที่ไหนสักแห่ง เพิ่มไฟล์จากโฟลเดอร์เหล่านี้ จดเส้นทางไปยังไฟล์ ทุกอย่างยอดเยี่ยม แต่! โปรเจ็กต์จะไม่ถูกสร้างขึ้นบนคอมพิวเตอร์เครื่องอื่น เนื่องจากเส้นทางทั้งหมดเป็นแบบสัมบูรณ์ กล่าวคือ พวกมันชี้ไปที่โฟลเดอร์เฉพาะบนคอมพิวเตอร์ของคุณ และในเครื่องอื่น คุณจะต้องทำตามขั้นตอนใหม่อีกครั้งเพื่อสร้างโปรเจ็กต์ใหม่ นี่เป็นการลบครั้งใหญ่ ดังนั้น ฉันมักจะสร้างโฟลเดอร์แยกต่างหากสำหรับโปรเจ็กต์ใหม่ โดยในนั้นฉันจะสร้างโฟลเดอร์ย่อยสำหรับ CMSIS, SPL และไลบรารีอื่นๆ ที่ใช้ และในโฟลเดอร์เหล่านี้ ฉันใส่ไฟล์ทั้งหมดที่ฉันต้องการในแต่ละโปรเจ็กต์เฉพาะ ตัวอย่างเช่น มาสร้างโฟลเดอร์ STM32F4_Test สำหรับโปรเจ็กต์ใหม่ของเราและโฟลเดอร์ต่อไปนี้ในนั้น:
ฉันใส่ไฟล์ที่จำเป็นทั้งหมดที่เราเพิ่มเมื่อสร้างโครงการในตอนต้นของบทความลงในโฟลเดอร์ CMSIS และ SPL ตอนนี้เราเปิดตัว Keil สร้างโปรเจ็กต์ใหม่และบันทึกไว้ในโฟลเดอร์ย่อย Project ของเรา เพื่อให้ไฟล์โปรเจ็กต์ทั้งหมดรวมอยู่ในที่เดียวและไม่ทำให้เกิดความวุ่นวาย)
โปรเจ็กต์ได้ถูกสร้างขึ้นแล้ว เช่นเคย เราเพียงแค่เพิ่มไฟล์ทั้งหมดจากโฟลเดอร์ STM32F4_CMSIS และ STM32F4_SPL เข้าไป เราใส่ไฟล์ test .c พร้อมด้วยฟังก์ชัน main() ลงในโฟลเดอร์ Source และเพิ่มลงในโปรเจ็กต์ด้วย สิ่งที่เหลืออยู่คือการกำหนดค่าการตั้งค่า =) ทุกอย่างเหมือนเดิม - ในช่องกำหนดที่เราเขียน:
USE_STDPERIPH_DRIVER,STM32F4XX
เราประกอบโปรเจ็กต์ - ไม่มีข้อผิดพลาด เที่ยวบินเป็นปกติ! โดยหลักการแล้วในที่สุดเราก็ได้สิ่งเดียวกัน แต่ตอนนี้โปรเจ็กต์จะถูกประกอบบนคอมพิวเตอร์เครื่องอื่นทันทีโดยไม่มีปัญหาใด ๆ ซึ่งสะดวกและมีประโยชน์มาก) ตอนนี้ไฟล์โปรเจ็กต์ทั้งหมดอยู่ใกล้ ๆ ในโฟลเดอร์เดียวกันอย่างแน่นอน และเส้นทางก็สัมพันธ์กันและไม่ต้องเปลี่ยน
นั่นคือทั้งหมด จริงๆ แล้ว ในอนาคตอันใกล้นี้เราจะทำอะไรบางอย่างเพื่อตั้งโปรแกรม STM32F4 แน่นอน แล้วพบกันใหม่เร็วๆ นี้!;)
โครงการเต็มจากบทความตัวอย่าง -
ในเอกสารเผยแพร่นี้ ฉันจะพยายามเน้นที่ประเด็นหลักสำหรับการเริ่มต้นใช้งานไมโครคอนโทรลเลอร์ STM32F10x อย่างรวดเร็วโดยอิงจากไลบรารีอุปกรณ์ต่อพ่วงมาตรฐานจากบริษัทผู้ผลิต STMicroelectronics
บทความนี้จะใช้ Eclipse CDT เป็นสภาพแวดล้อมการพัฒนา เนื่องจากจุดเน้นหลักจะอยู่ที่โค้ดโปรแกรม คุณจึงสามารถดำเนินการปรับแต่งทั้งหมดใน Code::Blocks ได้อย่างปลอดภัย
โครงสร้างโครงการทั่วไปสำหรับไมโครคอนโทรลเลอร์ ARM ได้อธิบายไว้ในบทความของฉัน
ที่นี่ฉันจะเตือนคุณสั้น ๆ ว่าในการสร้างโปรเจ็กต์สำหรับไมโครคอนโทรลเลอร์ ARM (โดยเฉพาะ STM32F10x) คุณจะต้องมีสคริปต์ตัวเชื่อมโยงและไฟล์ C-Startup
สคริปต์ลิงเกอร์คือไฟล์ที่มีคำแนะนำในการวางโค้ดโปรแกรมและข้อมูลในหน่วยความจำของไมโครคอนโทรลเลอร์ สามารถสั่งให้โค้ดโปรแกรมของคุณโหลดลงในหน่วยความจำโปรแกรม Flash หรือหน่วยความจำข้อมูล SRAM
ไมโครคอนโทรลเลอร์ที่มีจำนวนโปรแกรมและหน่วยความจำข้อมูลต่างกันต้องใช้สคริปต์โครงร่างที่แตกต่างกัน สามารถรับได้จากผู้ผลิตไมโครคอนโทรลเลอร์ - STMicroelectronics
คลายไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน STM32F10x จากไฟล์เก็บถาวร ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip
ประกอบด้วยโปรเจ็กต์ตัวอย่างสำหรับสภาพแวดล้อมการพัฒนาต่างๆ (IAR EWB, Keil uVision, Atollic True Studio ฯลฯ) สิ่งที่ใกล้เคียงที่สุดสำหรับเราคือ Atollic True Studio เนื่องจากเป็นการดัดแปลง Eclipse
ไปที่ไดเร็กทอรี Project/StdPeriph_Template/TrueSTUDIO ซึ่งมีไดเร็กทอรีย่อยหลายไดเร็กทอรี ซึ่งมีชื่อตรงกับชื่อของบอร์ดพัฒนา STM3210x-EVAL
ค้นหาว่าบอร์ดใดเหล่านี้ใช้สายไมโครคอนโทรลเลอร์เดียวกันกับของคุณ คัดลอกไฟล์ stm32_flash.ld จากไดเร็กทอรีที่เหมาะสมไปยังโปรเจ็กต์ของคุณ
นอกจากนี้ยังสามารถสร้างสคริปต์สากลที่จะเปลี่ยนเฉพาะจำนวนโปรแกรมและหน่วยความจำข้อมูลตามไมโครคอนโทรลเลอร์ที่ใช้
รหัสเริ่มต้น (C-Startup) สำหรับไมโครคอนโทรลเลอร์ STM32 สามารถเขียนเป็นภาษา C หรือ Assembler ได้
แม้ว่า STM32F10x Standard Peripheral Library (ตัวย่อ STM32F10x SPL) มักถูกวิพากษ์วิจารณ์ถึงข้อบกพร่อง แต่ก็เป็นวิธีที่ง่ายที่สุดในการเริ่มต้นอย่างรวดเร็วเมื่อเริ่มการเขียนโปรแกรม STM32
แต่คุณต้องการให้มีทางเลือกอื่นอยู่เสมอ จริงๆ แล้วก็มีหลายอย่าง เช่น การเขียนโปรแกรมในภาษาแอสเซมบลี :)
นี่เป็นเส้นทางที่ยากและไร้จุดหมายที่สุด วิธีที่สองคือการใช้ไลบรารี CMSIS ซึ่งมีไวยากรณ์สำหรับการเข้าถึงโครงสร้างภาษา C เพื่อเข้าถึงอุปกรณ์ต่อพ่วงไมโครคอนโทรลเลอร์ต่างๆ วิธีที่ง่ายและสมเหตุสมผลที่สุด (ในความคิดของฉัน) คือการใช้ไลบรารี
หากคุณไม่เห็นด้วยกับ STM32F10x SPL อย่างเด็ดขาด แสดงว่ามีทางเลือกอื่นสำหรับคุณโดยเฉพาะ นั่นก็คือไลบรารี libopencm3 ในนั้น ตัวอย่างจำนวนหลักจะกระจุกตัวอยู่ที่ซีรีส์หลักของไมโครคอนโทรลเลอร์ STM32F10x แต่เป็นเพียงเรื่องของเวลาก่อนที่ตัวอย่างสำหรับซีรีส์อื่นๆ (STM32F2xx/4xx) จะปรากฏขึ้น คุณสามารถเข้าร่วมโปรเจ็กต์ libopencm3 และเร่งกระบวนการนี้ได้ตลอดเวลา
มาตรฐาน CMSIS ยังเป็นทางเลือกสำหรับใช้ในโปรแกรมของคุณ
คุณสามารถทำได้โดยไม่ต้องใช้ความพยายามและเวลาในการปรับใช้ระดับ HAL (Hardware Abstraction Layer) ในภาษาการเขียนโปรแกรม C
วิธีนี้อาจเป็นวิธีเดียวที่ใช้ได้ในบางกรณี ตัวอย่างเช่น องค์กรของคุณใช้ชิปแบบกำหนดเองตามคอร์ประมวลผลที่พัฒนาโดย ARM และอุปกรณ์ต่อพ่วงเฉพาะอุตสาหกรรม
หรือคุณจำเป็นต้องใช้ซอฟต์แวร์ในภาษา C สำหรับไมโครคอนโทรลเลอร์ที่มีคอร์ ARM9 ซึ่งผู้ผลิตมุ่งเน้นไปที่การใช้ระบบปฏิบัติการสำเร็จรูป (Linux, QNX, Windows CE) ดังนั้นไลบรารีสำหรับการเขียนโปรแกรมในภาษา C ในรูปแบบบริสุทธิ์หรือใช้ร่วมกับ ผู้ผลิต RTOS ที่มีน้ำหนักเบาอาจไม่ได้จัดเตรียมไว้ให้
โชคดีที่ผู้ผลิตไมโครคอนโทรลเลอร์ที่ใช้คอร์ Cortex-M3 ช่วยให้นักพัฒนามีไลบรารีโค้ดจำนวนมาก นอกจากนี้ยังใช้กับไมโครคอนโทรลเลอร์ STM32 ด้วย
เรามาพิจารณาไลบรารี STM32F10x SPL กันต่อ เราจะพิจารณาโดยใช้ตัวอย่าง
คุณสามารถเปิดตัวอย่างนี้หรือสร้างโปรเจ็กต์ของคุณเองตั้งแต่เริ่มต้นเพื่อทำความเข้าใจกระบวนการทั้งหมดของสิ่งที่เกิดขึ้นได้ดียิ่งขึ้น
สำหรับกรณีที่ 2 ฉันจะแสดงรายการขั้นตอนที่จำเป็น:
- สร้างโปรเจ็กต์ว่างใหม่ใน Eclipse
- คัดลอกสคริปต์โครงร่างและเริ่มไฟล์ลงในโปรเจ็กต์
- สร้างใหม่หรือคัดลอกเทมเพลต Makefile
- เมื่อใช้ Makefile จากตัวอย่างของฉันเป็นเทมเพลต คุณจะต้องสร้างไดเร็กทอรี src, inc, bin, obj ภายในโปรเจ็กต์ และสร้างไดเร็กทอรีย่อย Debug และ Release ภายในไดเร็กทอรี bin และ obj
- คัดลอกไฟล์ต้นฉบับและส่วนหัวที่จำเป็นจากไลบรารี CMSIS และ STM32F10x SPL
- ทำการเปลี่ยนแปลงที่จำเป็นในส่วนการตั้งค่าผู้ใช้ของเทมเพลต Makefile หากใช้
- สร้างเป้าหมายใหม่ “Debug”, “cleanDebug”, “Release”, “cleanRelease”, “Program” ในหน้าต่าง Eclipse “make target”
- เปิดตัวเป้าหมาย “Debug” และตรวจสอบการดำเนินการในหน้าต่าง “คอนโซล”
เพื่อให้เข้าใจเนื้อหาได้ดีขึ้น ฉันจึงแบ่งบทความออกเป็นหลายย่อหน้าแยกกัน ซึ่งแต่ละย่อหน้าจะอธิบายเพียงแง่มุมเดียวในการทำงานกับไลบรารี STM32F10x SPL
การกำหนดค่า STM32F10x SPL โดยใช้คำจำกัดความของแมโคร
ในการกำหนดค่าไลบรารีจะใช้ค่ามาโครที่กำหนดไว้ล่วงหน้าซึ่งเราจะพิจารณาตอนนี้
สามารถตั้งค่าภายในไฟล์ส่วนหัวได้โดยใช้คำสั่งตัวประมวลผลล่วงหน้า #กำหนดหรือส่งค่าคำจำกัดความของมาโครผ่านคีย์ -Dคอมไพเลอร์ GCC
ในตัวอย่างของฉัน ฉันใช้วิธีที่สอง
ในตัวแปร Makefile กำหนดมีมาโครที่จำเป็นในการรวบรวมไลบรารี STM32F10x SPL
คำนิยามมาโคร STM32F10X_MDระบุว่าไมโครคอนโทรลเลอร์ที่ใช้เป็นของสายหรือไม่ ความหนาแน่นปานกลาง.
ซึ่งรวมถึงไมโครคอนโทรลเลอร์ที่มีหน่วยความจำแฟลชตั้งแต่ 64 ถึง 128 kB
ตารางต่อไปนี้แสดงรายการชื่อของมาโครสำหรับไมโครคอนโทรลเลอร์รุ่นต่างๆ:
ชื่อซีรีส์ | มาโคร | คำอธิบาย |
เส้นค่าความหนาแน่นต่ำ | STM32F10X_LD_VL | ด้วยความจุหน่วยความจำแฟลช 16 - 32 kB |
ความหนาแน่นต่ำ | STM32F10X_LD | ด้วยความจุหน่วยความจำแฟลช 16 - 32 kB |
เส้นค่าความหนาแน่นปานกลาง | STM32F10X_MD_VL | แฟลช - หน่วยความจำ 64 - 128kB |
ความหนาแน่นปานกลาง | STM32F10X_MD | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F101xx, STM32F102xx, STM32F103xx พร้อมหน่วยความจำแฟลช 64 - 128 kB |
เส้นค่าความหนาแน่นสูง | STM32F10X_HD_VL | ไมโครคอนโทรลเลอร์ของซีรีย์ STM32F100xx พร้อมปริมาตร แฟลช - หน่วยความจำ 256 - 512kB |
มีความหนาแน่นสูง | STM32F10X_HD | มีปริมาตร หน่วยความจำแฟลช 256 - 512kB |
XL-ความหนาแน่น | STM32F10X_XL | หน่วยความจำแฟลช 512 - 1024 กิโลไบต์ |
สายเชื่อมต่อ | STM32F10X_CL |
ในการตั้งค่าความถี่สัญญาณนาฬิกาของไมโครคอนโทรลเลอร์ คุณจะต้องยกเลิกหมายเหตุมาโครด้วยค่าความถี่สัญญาณนาฬิกาที่ต้องการในไฟล์ system_stm32f10x.c
#if กำหนดไว้ (STM32F10X_LD_VL) || (กำหนด STM32F10X_MD_VL) || (กำหนด STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 3600 0000 */ /* #กำหนด SYSCLK_FREQ_48MHz 48000000 */ /* #กำหนด SYSCLK_FREQ_56MHz 56000000 * / #กำหนด SYSCLK_FREQ_72MHz 72000000 #endif
#if กำหนดไว้ (STM32F10X_LD_VL) || (กำหนด STM32F10X_MD_VL) || (กำหนด STM32F10X_HD_VL) /* #กำหนด SYSCLK_FREQ_HSE HSE_VALUE */ #กำหนด SYSCLK_FREQ_24MHz 24000000 #อื่น /* #กำหนด SYSCLK_FREQ_HSE HSE_VALUE */ /* #กำหนด SYSCLK_FREQ_24MHz 24000000 */ /* #กำหนด SYSCLK_FREQ_36MHz 36000000 */ /* #กำหนด SYSCLK_FREQ_48MHz 48000000 */ /* #กำหนด SYSCLK_FREQ_56MHz 56000000 */ #กำหนด SYSCLK_FREQ_72MHz 72000000 #เอ็นดิฟ |
สันนิษฐานว่าต้องใช้เครื่องสะท้อนเสียงแบบควอตซ์ที่มีความถี่ 8 MHz สำหรับระบบหลักทั้งหมด
ไมโครคอนโทรลเลอร์ซีรีส์ต่างๆ ยกเว้นสายการเชื่อมต่อซึ่งจำเป็นต้องติดตั้งเครื่องสะท้อนเสียงควอทซ์ 25 MHz
หากคุณใช้ตัวสะท้อนเสียงแบบควอตซ์ที่มีค่าความถี่อื่น คุณจะต้องเปลี่ยนค่าของมาโคร HSE_VALUE ในไฟล์ส่วนหัว stm32f10x.h และปรับฟังก์ชันที่ขึ้นต่อกันทั้งหมดให้สอดคล้องกัน
วัตถุประสงค์ของมาโคร USE_STDPERIPH_DRIVER ไม่ใช่เรื่องยากที่จะคาดเดา - เพื่อใช้ไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน STM32F10x
USE_FULL_ASSERT - ใช้มาโคร ASSERT เพื่อดีบักโปรแกรม
การใช้มาโคร assert_param ในไลบรารี
ฟังก์ชันไลบรารี STM32F10x SPL ทั้งหมดใช้มาโคร assert_param เพื่อตรวจสอบอาร์กิวเมนต์
แมโครนี้จะตรวจสอบนิพจน์ที่เกี่ยวข้องกับอาร์กิวเมนต์ของฟังก์ชันที่กำลังทดสอบความเท่าเทียมกันเป็นศูนย์ หากค่าของนิพจน์เป็นศูนย์ ฟังก์ชันตัวจัดการข้อผิดพลาดอาร์กิวเมนต์ assert_failed จะถูกเรียก มิฉะนั้น (นิพจน์ไม่ใช่ศูนย์) การตรวจสอบอาร์กิวเมนต์จะสำเร็จ
คุณต้องใช้ฟังก์ชัน assert_failed ในโปรแกรมของคุณ
โดยจะแสดงข้อความแสดงข้อผิดพลาด ชื่อไฟล์ และหมายเลขบรรทัดโค้ดที่ทำให้เกิดข้อผิดพลาด
มาโคร debug_printf สามารถส่งออกผ่าน USART โดยใช้ไลบรารี new_lib มาตรฐาน หรือ ตัวอย่างเช่น ไลบรารีจาก Mr. Chen
#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(ไฟล์ uint8_t*, บรรทัด uint32_t) ( debug_printf("ค่าพารามิเตอร์ไม่ถูกต้อง: ไฟล์ %s ออนไลน์ %d\r\n", ไฟล์, (int) บรรทัด) ; ในขณะที่ (1) ( ) )/* assert_failed */ #endif/*USE_FULL_ASSERT*/
#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT เป็นโมฆะ assert_failed (ไฟล์ uint8_t *, บรรทัด uint32_t) debug_printf( "ค่าพารามิเตอร์ไม่ถูกต้อง: ไฟล์ %s ในบรรทัด %d\r\n", ไฟล์ , (int ) บรรทัด ); ในขณะที่(1) ) /* assert_failed */ #endif/*USE_FULL_ASSERT*/ |
ฟังก์ชัน assert_failed ที่นำมาใช้ในโค้ดของคุณจะใช้เมื่อมีการประกาศมาโคร USE_FULL_ASSERT เท่านั้น มิฉะนั้น รหัสการแก้ไขจุดบกพร่องทั้งหมดจะถูกแยกออกจากแหล่งที่มา ฟังก์ชันนี้ถูกนำไปใช้ในไฟล์ส่วนหัวการตั้งค่าไลบรารีไดรเวอร์ stm32f10x_conf.h
#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (เป็นโมฆะ)0: assert_failed((uint8_t *)__FILE__, __LINE__)) ถือเป็นโมฆะ assert_failed(ไฟล์ uint8_t*, บรรทัด uint32_t); #else #define assert_param(expr) ((เป็นโมฆะ)0) #endif /* USE_FULL_ASSERT */
#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (เป็นโมฆะ)0: assert_failed((uint8_t *)__FILE__, __LINE__)) เป็นโมฆะ assert_failed (ไฟล์ uint8_t *, บรรทัด uint32_t ) ; #อื่น #define assert_param(expr) ((เป็นโมฆะ)0) #endif /* USE_FULL_ASSERT */ |
ไม่มีอะไรจะอธิบายมากนักที่นี่ ลองดูตัวอย่างการใช้ assert_param
เป็นโมฆะ set_param(uint8_t * param, uint8_t value) ( assert_param(param != NULL); *param = value; )/*set_param*/
เป็นโมฆะ set_param (uint8_t * param, ค่า uint8_t) assert_param (พารามิเตอร์ != NULL ) ; * พารามิเตอร์ = ค่า ; ) /*set_param*/ |
ฟังก์ชันตั้งค่าของพารามิเตอร์ผ่านตัวชี้ที่ส่งผ่านเป็นอาร์กิวเมนต์ หากไม่ได้ประกาศมาโคร USE_FULL_ASSERT เราก็สามารถสรุปได้ว่าบรรทัดดังกล่าว
assert_param(param != NULL) ไม่ได้อยู่ในโค้ด มิฉะนั้นพารามิเตอร์จะถูกตรวจสอบในคำจำกัดความนี้
หากไม่ได้กำหนดตัวชี้ ค่า param != NULL จะเป็นเท็จ และฟังก์ชัน assert_failed จะถูกรัน ซึ่งจะส่งออกชื่อไฟล์และหมายเลขบรรทัดพร้อมข้อผิดพลาดผ่าน USART จากนั้นวนซ้ำ จึงป้องกันไม่ให้ค่าเป็น กำหนดให้กับที่อยู่ที่ไม่ได้กำหนดไว้ในหน่วยความจำ
คุณไม่จำเป็นต้องใช้มาโคร assert_param ในโค้ดของคุณ แต่ต้องใช้ในโค้ดไลบรารี
STM32F10x SPL ใช้ได้ทุกที่
สามารถใช้ฟังก์ชัน set_param พร้อมการตรวจสอบข้อผิดพลาดของอาร์กิวเมนต์ได้โดยไม่ต้องใช้ assert_param
#define ERROR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t value) ( int r = ERROR; if (param == NULL) ส่งคืน r; *param = value; r = OK; กลับ r ; )/*set_param*/
#define ข้อผิดพลาด (-1) #define ตกลง (0) int set_param (uint8_t * พารามิเตอร์, ค่า uint8_t) int r = ข้อผิดพลาด ; ถ้า (พารามิเตอร์ == NULL ) กลับ ร ; * พารามิเตอร์ = ค่า ; ร = ตกลง ; กลับ ร ; ) /*set_param*/ |
ไฟล์ C-Startup ในไลบรารี STM32F10x SPL
ในโค้ดเริ่มต้น ไมโครคอนโทรลเลอร์จะถูกเตรียมใช้งานเบื้องต้น มีการกำหนดค่าสแต็ก ส่วน BSS จะถูกรีเซ็ต และเรียกใช้ฟังก์ชันหลัก main()
โค้ดเริ่มต้นไม่มีความสัมพันธ์โดยตรงกับไลบรารี STM32F10x SPL อย่างไรก็ตาม ในโค้ดบูตนี้ ก่อนที่จะเรียกใช้ฟังก์ชัน main() ของโปรแกรม จะมีการเรียกฟังก์ชันการเริ่มต้นไมโครคอนโทรลเลอร์ SystemInit() ซึ่งเป็นส่วนหนึ่งของ CMSIS
สามารถพบได้ง่ายในไลบรารี CMSIS
ไปที่ไดเร็กทอรี Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO และคัดลอกไฟล์ที่ต้องการ สิ่งที่เหลืออยู่คือการค้นหาว่าไมโครคอนโทรลเลอร์ที่ใช้ในโครงการของคุณเป็นของบรรทัดใด
เมื่อต้องการทำเช่นนี้ ดูที่ตารางต่อไปนี้:
ชื่อซีรีส์ | ชื่อไฟล์ | คำอธิบาย |
เส้นค่าความหนาแน่นต่ำ | startup_stm32f10x_ld_vl.s | ไมโครคอนโทรลเลอร์ของซีรีย์ STM32F100xx พร้อมปริมาตร หน่วยความจำแฟลช 16 - 32kB |
ความหนาแน่นต่ำ | startup_stm32f10x_ld.s | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F101xx, STM32F102xx, STM32F103xx ด้วยความจุหน่วยความจำแฟลช 16 - 32 kB |
เส้นค่าความหนาแน่นปานกลาง | startup_stm32f10x_md_vl.s | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F100xx |
ความหนาแน่นปานกลาง | startup_stm32f10x_md.s | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F101xx, STM32F102xx, STM32F103xx ด้วยความจุหน่วยความจำแฟลช 64 - 128 kB |
เส้นค่าความหนาแน่นสูง | startup_stm32f10x_hd_vl.s | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F100xx |
มีความหนาแน่นสูง | startup_stm32f10x_hd.s | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F101xx, STM32F103xx ด้วยความจุหน่วยความจำแฟลช 256 - 512 kB |
XL-ความหนาแน่น | startup_stm32f10x_xl.s | ไมโครคอนโทรลเลอร์ซีรีส์ STM32F101xx, STM32F103xx ด้วยความจุหน่วยความจำแฟลช 512 - 1024 kB |
สายเชื่อมต่อ | startup_stm32f10x_cl.s | ไมโครคอนโทรลเลอร์ของซีรีส์ STM32F105xx และ STM32F107xx |
ไฟล์เริ่มต้นประกอบด้วยชื่อของตัวจัดการเวกเตอร์ขัดจังหวะและข้อยกเว้น แต่จะใช้เฉพาะตัวจัดการเวกเตอร์รีเซ็ตเท่านั้น ซึ่งภายในนั้นจะมีการดำเนินการเริ่มต้นทั้งหมดก่อนที่จะเรียกใช้ฟังก์ชัน main()
การใช้งานตัวจัดการข้อยกเว้นอื่นๆ ทั้งหมดถือเป็นความรับผิดชอบของแอปพลิเคชันโปรแกรมเมอร์ หากโปรแกรมของคุณไม่ได้ใช้ตัวจัดการใดๆ ก็ไม่จำเป็นต้องลงทะเบียนพวกมัน หากมีข้อยกเว้นเกิดขึ้น ระบบจะใช้ตัวจัดการเริ่มต้น - วนลูปโค้ดโปรแกรม
องค์ประกอบของไลบรารี CMSIS
ตามที่เขียนไว้ก่อนหน้าในเอกสารนี้ ไลบรารี CMSIS ช่วยให้สามารถเข้าถึงโมดูลต่อพ่วงไมโครคอนโทรลเลอร์ได้โดยใช้องค์ประกอบของโครงสร้างภาษา C
การใช้งานห้องสมุดนี้แบ่งออกเป็นสองส่วน ส่วนแรกให้การเข้าถึงขอบของคอร์ Cortex-M3 และส่วนที่สอง - ไปยังขอบของไมโครคอนโทรลเลอร์รุ่นเฉพาะ
เนื่องจากมาตรฐาน CMSIS นั้นเหมือนกันสำหรับไมโครคอนโทรลเลอร์ทั้งหมดที่มีแกน Cortex-M3 การใช้งานส่วนแรกจะเหมือนกันสำหรับผู้ผลิตทุกราย แต่ส่วนที่สองจะแตกต่างกันสำหรับผู้ผลิตแต่ละราย
CMSIS มีไฟล์ส่วนหัวและไฟล์ต้นฉบับหลายไฟล์ ส่วนแรกประกอบด้วยไฟล์:
- core_cm3.h
- core_cm3.c
ส่วนที่สองของ CMSIS ประกอบด้วยไฟล์ C-Startup และไฟล์ต่อไปนี้:
- stm32f10x.h
- system_stm32f10x.h
- system_stm32f10x.c
ไฟล์ส่วนหัว stm32f10x.h มีคำจำกัดความของแมโครสำหรับการเข้าถึงโมดูลต่อพ่วงของไมโครคอนโทรลเลอร์ stm32f10x
ไฟล์ system_stm32f10x.h และ system_stm32f10x.c ใช้การเริ่มต้นเริ่มต้นของไมโครคอนโทรลเลอร์
องค์ประกอบและการกำหนดค่าไลบรารี STM32F10x SPL
ไลบรารีประกอบด้วยไฟล์ต้นฉบับและส่วนหัวที่มีชื่อเดียวกันกับโมดูลต่อพ่วงที่มีคำนำหน้า stm32f10x_
ตัวอย่างเช่น การใช้งานการโต้ตอบกับโมดูล USART มีอยู่ในไฟล์ stm32f10x_usart.h และ stm32f10x_usart.c
มีหลักเกณฑ์สำหรับการตั้งชื่อองค์ประกอบไลบรารีและกฎการเข้ารหัสบางอย่าง ซึ่งอธิบายไว้ในเอกสารประกอบ
ไลบรารีประกอบด้วยการใช้งานไดรเวอร์สำหรับโมดูลไมโครคอนโทรลเลอร์ส่วนต่อพ่วง
ชื่อขององค์ประกอบไลบรารีใช้ตัวย่อต่อไปนี้สำหรับโมดูลอุปกรณ์ต่อพ่วง:
อักษรย่อ | โมดูลอุปกรณ์ต่อพ่วง |
เอดีซี | ตัวแปลงอนาล็อกเป็นดิจิทัล |
บีเคพี | ทะเบียนสำรอง |
สามารถ | สามารถเชื่อมต่อได้ |
ซีอีซี | ตัวควบคุมการบริโภค |
ซีอาร์ซี | โมดูลการคำนวณเช็คซัม |
ดีเอซี | ตัวแปลงดิจิตอลเป็นอนาล็อก |
DBGMCU | การดีบักไมโครคอนโทรลเลอร์ |
ดีเอ็มเอ | ตัวควบคุมการเข้าถึงหน่วยความจำโดยตรง |
ต่อ | ตัวควบคุมการขัดจังหวะภายนอก |
สศส | ตัวควบคุมหน่วยความจำภายนอก |
แฟลช | หน่วยความจำโปรแกรมแฟลช |
จีพีโอ | พอร์ต I/O เอนกประสงค์ |
ไอทูซี | อินเทอร์เฟซ I2C |
ไอทูเอส | อินเทอร์เฟซ I2S (เสียง) |
IWDG | ตัวจับเวลาสุนัขเฝ้าบ้านอิสระ |
NVIC | ตัวควบคุมการขัดจังหวะแบบซ้อน |
สปป | ตัวควบคุมพลังงาน |
อาร์ซีซี | รีเซ็ตและตัวควบคุมนาฬิกา |
อาร์ทีซี | ตัวควบคุมเรียลไทม์ (นาฬิกา) |
เอสดิโอ | อินเตอร์เฟซ SDIO |
เอสพีไอ | อินเตอร์เฟซเอสพีไอ |
SysTick | ตัวจับเวลาของระบบ |
ทิม | ตัวจับเวลาพื้นฐานหรือขั้นสูง |
USART | สากลแบบซิงโครนัสแบบอะซิงโครนัสอนุกรม ตัวรับส่งสัญญาณ |
WWDG | สุนัขเฝ้าบ้านหน้าต่าง |
จากตัวย่อเหล่านี้ ชื่อของโมดูลซอฟต์แวร์ของไลบรารีจึงถูกสร้างขึ้น คุณไม่จำเป็นต้องใช้โมดูลทั้งหมดในไลบรารี
เพื่อที่จะใช้เฉพาะโมดูลที่จำเป็นในโปรเจ็กต์ จะต้องกำหนดค่าไลบรารี
เพื่อวัตถุประสงค์เหล่านี้ แต่ละโปรเจ็กต์ที่ใช้ไลบรารี STM32F10x SPL ต้องมีไฟล์ส่วนหัว stm32f10x_conf.h
#รวม "stm32f10x_gpio.h" //#รวม "stm32f10x_i2c.h" //#รวม "stm32f10x_iwdg.h" //#รวม "stm32f10x_pwr.h" #รวม "stm32f10x_rcc.h"
#รวม "stm32f10x_gpio.h" //#รวม "stm32f10x_i2c.h" //#รวม "stm32f10x_iwdg.h" //#รวม "stm32f10x_pwr.h" #รวม "stm32f10x_rcc.h" |
หากต้องการเปิดใช้งานโมดูลที่จำเป็น คุณจะต้องยกเลิกหมายเหตุคำสั่ง #รวมด้วยไฟล์ส่วนหัวที่เกี่ยวข้อง
ไฟล์ส่วนหัว stm32f10x_conf.h รวมอยู่ใน stm32f10x.h ดังนั้นหากต้องการใช้ฟังก์ชันของไลบรารี STM32F10x SPL คุณจะต้องรวมไฟล์ส่วนหัว stm32f10x.h เพียงไฟล์เดียวในซอร์สโค้ดของคุณ
// ในไฟล์ stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif
ฉันขอย้ำอีกครั้งว่าโปรเจ็กต์ต้องกำหนดมาโคร USE_STDPERIPH_DRIVER, USE_FULL_ASSERT และมาโครที่ระบุชุดของไมโครคอนโทรลเลอร์ที่ใช้ (เช่น STM32F10X_MD สำหรับเส้นความหนาแน่นปานกลาง)
หากคุณใช้ค่าความถี่ควอตซ์มาตรฐานและตัวควบคุมทำงานที่ความถี่สัญญาณนาฬิกาสูงสุด 72 MHz คุณจะไม่ต้องเปลี่ยนแปลงสิ่งอื่นใด
คุณต้องเพิ่มรายการไฟล์ไลบรารีเพื่อคอมไพล์เป็น Makefile
ตัวอย่างเช่น:
SRC += stm32f10x_rcc.c SRC += stm32f10x_gpio.c
SRC += stm32f10x_rcc ค SRC += stm32f10x_gpio ค |
การใช้ไลบรารี STM32F10x SPL กลไกการทำงาน
ในการเริ่มการเขียนโปรแกรมโดยใช้ไลบรารีอุปกรณ์ต่อพ่วง วิธีที่ง่ายที่สุดคือการดูตัวอย่างที่มาพร้อมกับไลบรารี แต่ถึงกระนั้น เพื่อให้เข้าใจโค้ดของตัวอย่างเหล่านี้ คุณต้องมีความรู้พื้นฐานเกี่ยวกับไวยากรณ์และการใช้งานไลบรารี
โมดูลไมโครคอนโทรลเลอร์ส่วนต่อพ่วงที่ระบุไว้ก่อนหน้านี้ทั้งหมดจะถูกปิดการใช้งานในตอนแรก โดยไม่มีการจ่ายสัญญาณนาฬิกาให้โมดูลเหล่านั้น และโมดูลเหล่านั้นจะไม่ใช้ไฟฟ้า
หากต้องการใช้โมดูลต่อพ่วง คุณต้องจัดเตรียมสัญญาณนาฬิกาก่อน สัญญาณนาฬิกามาจากนาฬิกา RCC และโมดูลรีเซ็ต
เพื่อวัตถุประสงค์เหล่านี้ ห้องสมุดมีฟังก์ชันดังต่อไปนี้:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, เปิดใช้งาน); RCC_APB2PeriphClockCmd(RCC_APB2PPPx, เปิดใช้งาน); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, เปิดใช้งาน);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, เปิดใช้งาน); RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx, เปิดใช้งาน); RCC_APB1PeriphClockCmd (RCC_APB1PPPx, เปิดใช้งาน); |
ในที่นี้ PPP หมายถึงชื่อของชื่อย่อของโมดูล (เช่น ADC หรือ USART) และ x คือหมายเลขของโมดูลต่อพ่วง
ก่อนอื่น คุณต้องค้นหาว่าโมดูลที่คุณใช้เชื่อมต่อกับบัสตัวใด
โดยรวมแล้ว ไมโครคอนโทรลเลอร์ที่มีสถาปัตยกรรมหลัก Cortex-M3 มีบัสสามตัว:
บัสคำสั่ง บัสข้อมูล และบัสระบบ บัสคำสั่งเชื่อมต่อแกนหลักกับหน่วยความจำโปรแกรมแฟลช บัสข้อมูลและระบบจะรวมกันเป็นเมทริกซ์บัส AHB (ARM Hi-Speed Bus) ซึ่งทำงานที่ความถี่คอร์ อย่างไรก็ตาม ความถี่บัส AHB สามารถลดลงได้โดยการติดตั้งตัวแบ่ง บัส AHB เชื่อมต่ออุปกรณ์ความเร็วสูง เช่น แกนหลักและโมดูล DMA
อุปกรณ์ I/O เชื่อมต่อกับบัส AHB ผ่านบัสกลาง APB1 และ APB2 (ARM Peripheral Bus)
ความถี่การทำงานสูงสุดของบัส APB2 คือ 72 MHz ซึ่งเป็นความถี่ของบัส APB1
จำกัดไว้ที่ 36MHz
คุณสามารถดูได้ว่าโมดูลต่อพ่วงที่คุณใช้เชื่อมต่ออยู่กับบัสใดบ้างจากเอกสารประกอบ หรือดูในไฟล์ส่วนหัว stm32f10x_rcc.h
เปิดไฟล์นี้และค้นหาค่า RCC_AHBPeriph, RCC_APB1Periph และ RCC_APB2Periph ตามลำดับ
#กำหนด RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #กำหนด RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #กำหนด RCC_AHBPeriph_SRAM ((uint32_t)0x00000004) #กำหนด RCC_AHBPeriph_FLITF ((uint32_t) 0x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)
#กำหนด RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004) #define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040) |
ตามชื่อของมาโครเราจะกำหนดว่าโมดูลใดเชื่อมต่อกับบัสใด คุณยังสามารถใช้สามัญสำนึกในการพิจารณาว่ายางใดเป็นของหนึ่งในสามยางเหล่านี้ ตัวอย่างเช่น โมดูล USART เป็นอุปกรณ์อินพุต/เอาต์พุต ซึ่งหมายความว่าโมดูลเชื่อมต่อกับหนึ่งในบัส APB USART เป็นอินเทอร์เฟซความเร็วค่อนข้างต่ำ ดังนั้นจึงอาจเชื่อมต่อกับบัส APB1
#กำหนด RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #กำหนด RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #กำหนด RCC_APB1Periph_UART4 ((uint32_t)0x00080000) #กำหนด RCC_APB1Periph_UART5 ((uint32_t)0x00100000)
หลังจากส่งสัญญาณนาฬิกาไปยังโมดูลต่อพ่วงแล้ว คุณสามารถกำหนดค่าพารามิเตอร์ได้โดยการเรียกใช้ฟังก์ชันการเริ่มต้น:
PPP_Init(PPP, &PPP_InitStructure);
PPP_Init (พีพีพี , & แอมป์ ; PPP_InitStructure ) ; |
เนื่องจากต้องส่งพารามิเตอร์จำนวนมากไปยังฟังก์ชันการเริ่มต้นเพื่อเริ่มต้นโมดูลต่อพ่วง ตัวชี้ไปยังโครงสร้างจึงถูกใช้เป็นอาร์กิวเมนต์ ต้องสร้างโครงสร้างด้วยพารามิเตอร์การเริ่มต้นในหน่วยความจำก่อนเรียกใช้ฟังก์ชันการเริ่มต้น องค์ประกอบของโครงสร้างจะต้องได้รับการกำหนดค่าที่จำเป็น:
PPP_InitTypeDef PPP_InitStructure = (val1, val2, ..., valN);/* การเริ่มต้นโครงสร้างเมื่อมีการประกาศ */
คุณสามารถสร้างโครงสร้างก่อนแล้วจึงกำหนดค่าที่จำเป็นให้กับองค์ประกอบ:
PPP_InitTypeDef PPP_InitStructure; PPP_InitStructure.member1 = val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN = valN;
PPP_InitTypeDef PPP_InitStructure ; โครงสร้าง PPP_Init สมาชิก1 = val1 ; โครงสร้าง PPP_Init สมาชิก2 = val2 ; โครงสร้าง PPP_Init สมาชิก N = valN ; |
ลองดูตัวอย่างจากโปรเจ็กต์ stm32f10xQuickstart:
GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, เปิดใช้งาน); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed \u003d GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitTypeDef GPIO_InitStructure ; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, เปิดใช้งาน); GPIO_InitStructure GPIO_พิน = GPIO_พิน_12 ; GPIO_InitStructure GPIO_ความเร็ว = GPIO_Speed_50MHz ; GPIO_InitStructure GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_Init(GPIOC, และ GPIO_InitStructure); |
องค์ประกอบของโครงสร้าง GPIO_InitStructure ได้รับการกำหนดค่าของหมายเลขพิน โหมด และความเร็วของพอร์ต
โดยการเรียกใช้ฟังก์ชัน GPIO_Init บรรทัดที่ 12 ของพอร์ต GPIOC จะถูกเตรียมใช้งาน
อาร์กิวเมนต์แรกของฟังก์ชัน GPIO_Init คือตัวชี้ไปยังพื้นที่หน่วยความจำของอุปกรณ์ต่อพ่วง GPIOC ซึ่งแปลงเป็นตัวชี้เป็นโครงสร้าง GPIO_TypeDef
// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) typedef struct ( __IO u int32_t CRL; __IO uint32_t CRH ; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; ) GPIO_TypeDef;
// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #กำหนด APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) โครงสร้าง typedef IO uint32_t CRL ; IO uint32_t CRH ; IO uint32_t IDR ; IO uint32_t ODR ; IO uint32_t BSRR ; IO uint32_t BRR ; IO uint32_t LCKR ; ) GPIO_TypeDef ; |
โครงสร้าง GPIO_InitStructure เป็นประเภท GPIO_InitTypeDef ตามที่อธิบายไว้ในไฟล์ส่วนหัว
stm32f10x_gpio.h:
//stm32f10x_gpio.h โครงสร้าง typedef ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; ) GPIO_InitTypeDef; typedef enum ( GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz )GPIOSpeed_TypeDef; typedef enum ( GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18 )GPIOMode_TypeDef;
//stm32f10x_gpio.h โครงสร้าง typedef uint16_t GPIO_พิน ; GPIOSpeed_TypeDef GPIO_ความเร็ว; GPIOMode_TypeDef GPIO_Mode ; ) GPIO_InitTypeDef ; typedef enum GPIO_Speed_10MHz = 1, GPIO_ความเร็ว_2MHz, GPIO_ความเร็ว_50MHz ) GPIOSpeed_TypeDef ; typedef enum (GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04 , GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C , GPIO_Mode_AF_PP = 0x18 ) GPIOMode_TypeDef ; |
อย่างที่คุณเห็นทั้งประเภทที่ผู้ใช้กำหนดเช่น GPIOSpeed_TypeDef และประเภทข้อมูลที่มีค่าเฉพาะเพื่อความสะดวกในการเริ่มต้นการลงทะเบียนอุปกรณ์ต่อพ่วงเช่น GPIOMode_TypeDef สามารถใช้เป็นประเภทข้อมูลของโครงสร้างเริ่มต้นได้
มีการจัดสรร 4 บิตสำหรับการกำหนดค่าแต่ละพิน GPIO
รูปภาพต่อไปนี้แสดงรูปแบบของศูนย์บิตของ GPIO:
โหมด – โหมดการทำงานของเอาต์พุต (อินพุต/เอาต์พุต) แม่นยำยิ่งขึ้นค่าเหล่านี้มีขนาดใหญ่กว่าเล็กน้อย พอร์ตที่กำหนดค่าเป็นพอร์ตเอาท์พุตมีข้อ จำกัด เกี่ยวกับความถี่สูงสุดของสัญญาณเอาท์พุต
โหมด | คำอธิบาย |
00 | ทางเข้า |
01 | ความถี่เอาต์พุตสูงถึง 10 MHz |
10 | ความถี่เอาต์พุตสูงสุด 2 MHz |
11 | ความถี่เอาท์พุตสูงถึง 50 MHz |
CNF – บิตการกำหนดค่าเอาต์พุต ขึ้นอยู่กับโหมดการทำงาน:
ยอมรับว่าโครงสร้างการลงทะเบียนการกำหนดค่าพินนี้จะทำให้ไม่สะดวกอย่างยิ่งในการตั้งค่าบิตทั้งหมดสำหรับการกำหนดค่าด้วยตนเอง การทำเช่นนี้จะง่ายกว่ามากโดยใช้ฟังก์ชันไลบรารี GPIO_Init
หลังจากที่คุณเตรียมใช้งานโมดูลต่อพ่วงแล้ว จะต้องเปิดใช้งานโดยใช้ฟังก์ชัน PPP_Cmd:
PPP_Cmd(พีพีพี, เปิดใช้งาน);
PPP_Cmd(พีพีพี, เปิดใช้งาน); |
ไม่มีฟังก์ชันนี้สำหรับโมดูล GPIO หลังจากการกำหนดค่าเริ่มต้น คุณสามารถใช้หมุด GPIO ได้ทันที ต้องจำไว้ว่าไลบรารีมีอินเทอร์เฟซสำหรับฮาร์ดแวร์ไมโครคอนโทรลเลอร์เท่านั้น หากโมดูลฮาร์ดแวร์ไม่มีแฟล็กการเปิดใช้งาน/ปิดใช้งาน การเรียกใช้ฟังก์ชัน PPP_Cmd(PPP, เปิดใช้งาน)เป็นไปไม่ได้.
เพื่อควบคุมสถานะของพิน GPIOx ในโหมดเอาต์พุตและอ่านค่าในโหมดอินพุตหรือเอาต์พุต ไลบรารีจะมีฟังก์ชันต่อไปนี้:
โมฆะ GPIO_SetBits (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin); โมฆะ GPIO_ResetBits (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
โมฆะ GPIO_SetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ; โมฆะ GPIO_ResetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin ) ; uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_พิน) ; uint16_tGPIO_ReadOutputData(GPIO_TypeDef* GPIOx) ; uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_พิน) ; uint16_tGPIO_ReadInputData(GPIO_TypeDef* GPIOx) ; |
โมดูลต่อพ่วงที่เหลือได้รับการกำหนดค่าและทำงานในลักษณะเดียวกัน อย่างไรก็ตาม มีความแตกต่างบางประการเนื่องจากลักษณะเฉพาะของโมดูลฮาร์ดแวร์เฉพาะ ดังนั้น ฉันขอแนะนำอย่างยิ่งให้คุณดูตัวอย่างการใช้โมดูลที่เลือกสำหรับไลบรารี STM32F10x SPL ก่อน
การจัดการกับการขัดจังหวะและข้อยกเว้น
แกน Cortex-M3 มีตัวควบคุมขัดจังหวะแบบเวกเตอร์ที่ซ้อนกัน คอนโทรลเลอร์รองรับแหล่งที่มาได้มากถึง 240 แหล่งซึ่งอาจทำให้แกนประมวลผลขัดจังหวะได้ จำนวนเวกเตอร์ที่เป็นไปได้จาก 240 ตัวที่สามารถนำไปใช้กับไมโครคอนโทรลเลอร์รุ่นใดรุ่นหนึ่งนั้นขึ้นอยู่กับผู้ผลิต ไมโครคอนโทรลเลอร์ Stm32f10x สามารถมีเวกเตอร์เหล่านี้ได้สูงสุด 43 ตัว เส้นขัดจังหวะเหล่านี้เรียกว่ามาสก์ได้ นอกจากนี้ ยังมีเวกเตอร์อินเทอร์รัปต์คอร์ Cortex-M3 15 ตัว และอินเทอร์รัปต์ EXTI ภายนอกที่ไม่สามารถปกปิดได้ 1 ตัว
คอนโทรลเลอร์รองรับการขัดจังหวะแบบซ้อน ซึ่งการขัดจังหวะอื่นสามารถเกิดขึ้นได้ภายในตัวจัดการเดียว ในเรื่องนี้ แต่ละแหล่งสัญญาณขัดจังหวะจะมีลำดับความสำคัญของตัวเอง รองรับระดับความสำคัญขัดจังหวะ 16 ระดับ
เวกเตอร์การขัดจังหวะคอร์ Cortex-M3 มีค่าลำดับความสำคัญสูงสุด
ระดับการขัดจังหวะสูงสุดสามระดับถูกกำหนดให้กับเวกเตอร์และไม่สามารถเปลี่ยนแปลงได้:
ตัวเลข | ตัวจัดการ | ลำดับความสำคัญ | คำอธิบาย |
1 | รีเซ็ต_ตัวจัดการ | -3(สูงสุด) | รีเซ็ตเวกเตอร์ |
2 | NMI_ตัวจัดการ | -2 | การขัดจังหวะแบบไม่ปกปิด |
3 | HardFault_Handler | -1 | ภาวะฉุกเฉิน |
เวกเตอร์ขัดจังหวะอื่นๆ ทั้งหมดสามารถกำหนดระดับความสำคัญได้ตั้งแต่ 0 ถึง 15
ระดับความสำคัญสูงสุดสอดคล้องกับค่าที่ต่ำกว่า ลำดับความสำคัญสามารถกำหนดได้ไม่เฉพาะกับเวกเตอร์แต่ละตัวเท่านั้น แต่ยังรวมถึงเวกเตอร์ทั้งกลุ่มด้วย คุณสมบัตินี้ช่วยให้ทำงานกับเวกเตอร์ขัดจังหวะจำนวนมากได้ง่ายขึ้น
ในการตั้งค่ากลุ่มลำดับความสำคัญ จะใช้ฟังก์ชันจากไลบรารี STM32F10x SPL
สวัสดีทุกคน. ดังที่คุณจำได้ในบทความที่แล้ว เราได้กำหนดค่าแพ็คเกจซอฟต์แวร์ให้ทำงานกับไมโครคอนโทรลเลอร์ STM32 และคอมไพล์โปรแกรมแรก ในโพสต์นี้ เราจะทำความคุ้นเคยกับสถาปัตยกรรมของบอร์ด ไมโครคอนโทรลเลอร์ และไลบรารี่ที่ใช้งานได้
ด้านล่างเป็นภาพของคณะกรรมการ การค้นพบ STM32F3 โดยที่: 1 — เซ็นเซอร์ MEMS L3GD20 ไจโรสโคปดิจิตอล 3 แกน 2 - ระบบ MEMS ในกล่องประกอบด้วยตัวตรวจวัดความเร่งเชิงเส้นแบบดิจิทัล 3 แกนและเซ็นเซอร์ภูมิศาสตร์แม่เหล็กแบบดิจิทัล 3 แกน LSM303DLHC 4 – LD1 (PWR) – แหล่งจ่ายไฟ 3.3V 5 – LD2 – ไฟ LED สีแดง/เขียว ค่าเริ่มต้นคือสีแดง สีเขียวหมายถึงการสื่อสารระหว่าง ST-LINK/v2 (หรือ V2-B) และพีซี ฉันมี ST-LINK/v2-B รวมถึงตัวบ่งชี้พอร์ต USB แบบกำหนดเอง 6. -LD3/10 (สีแดง), LD4/9 (สีน้ำเงิน), LD5/8 (สีส้ม) และ LD6/7 (สีเขียว) ในโพสต์ที่แล้ว เราได้แฟลช LD4 LED 7. – สองปุ่ม: ผู้ใช้ผู้ใช้และรีเซ็ต 8. - ผู้ใช้ USB พร้อมขั้วต่อ Mini-B9 - ดีบักเกอร์ USB/โปรแกรมเมอร์ ST-LINK/V2. 1 0. - ไมโครคอนโทรลเลอร์ STM32F303VCT6. 11. — เครื่องกำเนิดความถี่สูงภายนอก 8 MHz 12. – ควรมีเครื่องกำเนิดความถี่ต่ำอยู่ที่นี่ แต่น่าเสียดายที่ไม่มีการบัดกรี 13. – SWD – อินเทอร์เฟซ 14. – จัมเปอร์สำหรับเลือกการตั้งโปรแกรมตัวควบคุมภายนอกหรือภายใน ในกรณีแรกจะต้องถูกถอดออก 15 – Jumper JP3 – จัมเปอร์ที่ออกแบบมาเพื่อเชื่อมต่อแอมป์มิเตอร์เพื่อวัดปริมาณการใช้ตัวควบคุม ชัดเจนว่าถ้าลบออกไป หินของเราก็จะไม่เริ่มทำงาน 16. – STM32F103C8T6 มีบอร์ดดีบักอยู่ 17. - ตัวควบคุม LD3985M33R พร้อมแรงดันตกคร่อมต่ำและระดับเสียง 150mA, 3.3V
ตอนนี้เรามาดูสถาปัตยกรรมของไมโครคอนโทรลเลอร์ STM32F303VCT6 กันดีกว่า ลักษณะทางเทคนิค: เคส LQFP-100, แกน ARM Cortex-M4, ความถี่คอร์สูงสุด 72 MHz, ความจุหน่วยความจำโปรแกรม 256 KB, ประเภทหน่วยความจำโปรแกรม FLASH, ความจุ RAM SRAM 40 KB, RAM 8 KB, จำนวนอินพุต/เอาต์พุต 87, อินเทอร์เฟซ ( CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), อุปกรณ์ต่อพ่วง (DMA, I2S, POR, PWM, WDT), ADC/DAC 4*12 บิต/2*12 บิต, แรงดันไฟฟ้า 2 ... 3.6 V อุณหภูมิในการทำงาน –40...+85 C ในรูปด้านล่างเป็น pinout โดยที่เราเห็นพอร์ต I/O 87 พอร์ต โดย 45 พอร์ตเป็น I/O ปกติ (TC, TTa) 42 พอร์ตทน 5 โวลต์ I /Os (FT, FTf) – เข้ากันได้กับ 5 V (บนบอร์ดมีพิน 5V ทางด้านขวา, 3.3V ทางด้านซ้าย) สาย I/O ดิจิทัลแต่ละสายสามารถทำหน้าที่เป็นสาย I/O ทั่วไปได้ ปลายทางหรือฟังก์ชันทางเลือก เมื่อโครงการดำเนินไป เราจะค่อยๆ ทำความคุ้นเคยกับบริเวณรอบนอก
พิจารณาแผนภาพบล็อกด้านล่าง หัวใจคือแกน ARM Cortex-M4 32 บิตที่ทำงานได้ถึง 72 MHz มีหน่วย FPU ทศนิยมในตัวและหน่วยป้องกันหน่วยความจำ MPU เซลล์ติดตามมาโครในตัว - Embedded Trace Macrocell (ETM) ซึ่งสามารถใช้เพื่อตรวจสอบกระบวนการประมวลผลของโปรแกรมหลักภายในไมโครคอนโทรลเลอร์ พวกเขาสามารถส่งสัญญาณการสังเกตเหล่านี้ได้อย่างต่อเนื่องผ่านหน้าสัมผัส ETM ตราบใดที่อุปกรณ์ยังทำงานอยู่ NVIC (ตัวควบคุมการขัดจังหวะเวกเตอร์แบบซ้อน) - โมดูลควบคุมการขัดจังหวะ TPIU (หน่วยเชื่อมต่อพอร์ตการติดตาม) ประกอบด้วยหน่วยความจำ FLASH – 256 KB, SRAM 40 KB, RAM 8 KB ระหว่างคอร์และหน่วยความจำคือบัสเมทริกซ์ซึ่งช่วยให้อุปกรณ์เชื่อมต่อได้โดยตรง นอกจากนี้ เรายังเห็นบัสเมทริกซ์ AHB และ APB สองประเภท โดยประเภทแรกมีประสิทธิภาพมากกว่าและใช้ในการสื่อสารส่วนประกอบภายในความเร็วสูง และประเภทหลังสำหรับอุปกรณ์ต่อพ่วง (อุปกรณ์อินพุต/เอาต์พุต) คอนโทรลเลอร์มี ADC 12 บิต (ADC) (5Mbit/s) 4 ตัว และเซ็นเซอร์อุณหภูมิ 1 ตัว ตัวเปรียบเทียบ 7 ตัว (GP Comparator1...7) เครื่องขยายสัญญาณปฏิบัติการที่ตั้งโปรแกรมได้ 4 ตัว (OpAmp1...4) (PGA (อาร์เรย์เกนแบบตั้งโปรแกรมได้) ), 2 ช่อง DAC 12 บิต (DAC), RTC (นาฬิกาเรียลไทม์), ตัวจับเวลาจ้องจับผิดสองตัว - อิสระและมีหน้าต่าง (WinWatchdog และ Ind. WDG32K), 17 วัตถุประสงค์ทั่วไปและตัวจับเวลามัลติฟังก์ชั่น
โดยทั่วไปแล้ว เราพิจารณาสถาปัตยกรรมคอนโทรลเลอร์ ตอนนี้ดูที่ไลบรารีซอฟต์แวร์ที่มีอยู่ เมื่อสร้างภาพรวมแล้ว เราสามารถเน้นสิ่งต่อไปนี้: CMSIS, SPL และ HAL มาดูแต่ละตัวอย่างโดยใช้ตัวอย่างง่ายๆ ของการกะพริบไฟ LED
1). ซีเอ็มซิส(มาตรฐานซอฟต์แวร์อินเทอร์เฟซไมโครคอนโทรลเลอร์ Cortex) - ไลบรารีมาตรฐานสำหรับ Cortex®-M ให้การสนับสนุนอุปกรณ์และลดความซับซ้อนของอินเทอร์เฟซซอฟต์แวร์ CMSIS มอบอินเทอร์เฟซที่สม่ำเสมอและเรียบง่ายให้กับเคอร์เนล อุปกรณ์ต่อพ่วง และระบบปฏิบัติการแบบเรียลไทม์ การใช้งานเป็นวิธีการเขียนโปรแกรมแบบมืออาชีพเพราะ... เกี่ยวข้องกับการเขียนโดยตรงไปยังทะเบียน ดังนั้น การอ่านและการศึกษาเอกสารข้อมูลอย่างต่อเนื่องจึงมีความจำเป็น เป็นอิสระจากผู้ผลิตฮาร์ดแวร์
CMSIS มีส่วนประกอบดังต่อไปนี้:
- CMSIS-CORE: การเริ่มต้นระบบและการเข้าถึงอุปกรณ์ต่อพ่วงที่สอดคล้องกัน
- CMSIS-RTOS: การดำเนินการซอฟต์แวร์แบบเรียลไทม์ตามที่กำหนด (การดำเนินการตามกำหนดเวลาของซอฟต์แวร์แบบเรียลไทม์)
— CMSIS-DSP: การใช้งานการประมวลผลสัญญาณดิจิตอลอย่างรวดเร็ว
- CMSIS-Driver: อินเทอร์เฟซต่อพ่วงทั่วไปสำหรับมิดเดิลแวร์และโค้ดแอปพลิเคชัน (อินเทอร์เฟซต่อพ่วงทั่วไปสำหรับมิดเดิลแวร์และโค้ดแอปพลิเคชัน)
— CMSIS-Pack: เข้าถึงส่วนประกอบซอฟต์แวร์ที่นำกลับมาใช้ใหม่ได้ง่าย (เข้าถึงส่วนประกอบซอฟต์แวร์ที่นำกลับมาใช้ใหม่ได้ง่าย)
- CMSIS-SVD: การดูอุปกรณ์และอุปกรณ์ต่อพ่วงที่สอดคล้องกัน
- CMSIS-DAP: การเชื่อมต่อกับฮาร์ดแวร์ประเมินผลราคาประหยัด ซอฟต์แวร์แก้ไขข้อบกพร่อง
ตัวอย่างเช่น ลองเขียนโปรแกรม - ไฟ LED กระพริบ สำหรับสิ่งนี้ เราจำเป็นต้องมีเอกสารที่อธิบายการลงทะเบียน ในกรณีของฉัน RM0316 คู่มืออ้างอิง STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE MCU ที่ใช้ ARM ® ขั้นสูง ตลอดจนคำอธิบายของขาเฉพาะที่รับผิดชอบ DS9118: Cortex®-M4 ที่ใช้ ARM® 32b MCU+FPU, สูงสุด 256KB Flash+ 48KB SRAM, 4 ADC, 2 DAC ch., 7 comp, 4 PGA, ตัวจับเวลา, 2.0-3.6 V.อันดับแรกเราจะทำการโอเวอร์คล็อกพอร์ตในโปรแกรมเพราะว่า ตามค่าเริ่มต้น ทุกอย่างจะถูกปิดใช้งาน ซึ่งจะทำให้การใช้พลังงานลดลง เปิดคู่มืออ้างอิงและดูที่ส่วนรีเซ็ตและการควบคุมนาฬิกา จากนั้น RCC register map และดูว่ารีจิสเตอร์ใดที่รับผิดชอบในการเปิดใช้งาน IOPEEN
เรามาดูคำอธิบายของการตอกบัตรของอุปกรณ์ต่อพ่วงของรีจิสเตอร์นี้กัน AHB อุปกรณ์ต่อพ่วงเปิดใช้งานการลงทะเบียน (RCC_AHBENR)โดยเราจะเห็นว่าพอร์ตนี้อยู่ภายใต้บิตที่ 21 เปิด RCC->AHBENR|=(1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODER|=0×10000 . อย่างที่สองคือสำหรับเปิดระดับต่ำ/สูงที่ขา ด้านล่างเป็นโปรแกรม:
#รวม"stm32f3xx.h " // ไฟล์ส่วนหัวของไมโครคอนโทรลเลอร์
ไม่ได้ลงนาม int i;
เป็นโมฆะล่าช้า () (
สำหรับ (i=0;i<500000;i++);
}
int main (เป็นโมฆะ) (
RCC->AHBENR|=(1<<21);
GPIOE->โมเดอเรเตอร์|=0×10000;
ในขณะที่ (1)(
ล่าช้า();
GPIOE->ODR|=0×100;
ล่าช้า();
GPIOE->ODR&=~(0×100);
} }
2). สปล(ไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน)- ไลบรารีนี้มีวัตถุประสงค์เพื่อรวมโปรเซสเซอร์ทั้งหมดจาก ST Electronics ออกแบบมาเพื่อปรับปรุงความสามารถในการพกพาโค้ดและมุ่งเป้าไปที่นักพัฒนามือใหม่เป็นหลัก ST กำลังทำงานเพื่อทดแทน SPL ที่เรียกว่า "โลว์เลเยอร์" ที่เข้ากันได้กับ HAL ไดรเวอร์ Low Layer (LL) ได้รับการออกแบบมาเพื่อมอบเลเยอร์ที่เน้นการใช้งานโดยผู้เชี่ยวชาญซึ่งเกือบจะมีน้ำหนักเบาและอยู่ใกล้กับฮาร์ดแวร์มากกว่า HAL นอกจาก HAL แล้ว LL API ยังมีให้บริการอีกด้วย ตัวอย่างโปรแกรมเดียวกันใน SPL
#รวม
#รวม
#รวม
#กำหนด LED GPIO_Pin_8
int หลัก() (
ยาวฉัน;
GPIO_InitTypeDef gpio;
// ไฟ LED สีฟ้าเชื่อมต่อกับพอร์ต E, ขา 8 (บัส AHB)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, เปิดใช้งาน);
// กำหนดค่าพอร์ต E (LED)
GPIO_StructInit(&gpio); //ประกาศและเริ่มต้นตัวแปรโครงสร้างข้อมูล
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_Pin = LED;
GPIO_Init(GPIOE, &gpio);
// ไฟ LED กะพริบ
ในขณะที่ (1) (
//บน
GPIO_SetBits(GPIOE, LED);
สำหรับ (i = 0; i< 500000; i++);
//ปิดหมด.
GPIO_ResetBits(GPIOE, LED);
สำหรับ (i = 0; i< 500000; i++);
} }
แต่ละฟังก์ชันมีการอธิบายไว้ในเอกสารทางเทคนิค UM1581 คู่มือผู้ใช้คำอธิบายของ STM32F30xx/31xx Standard Peripheral Library. ที่นี่เราเชื่อมต่อไฟล์ส่วนหัวสามไฟล์ที่มีข้อมูล โครงสร้าง ฟังก์ชันการควบคุมการรีเซ็ตและการซิงโครไนซ์ที่จำเป็น รวมถึงการกำหนดค่าพอร์ตอินพุต/เอาท์พุต
3). ฮาล- (ระดับการเข้าถึงฮาร์ดแวร์, เลเยอร์นามธรรมของฮาร์ดแวร์)- ห้องสมุดทั่วไปอีกแห่งเพื่อการพัฒนา ซึ่งโปรแกรม CubeMX สำหรับการกำหนดค่าที่เราใช้ในบทความที่แล้วก็ได้รับการเผยแพร่เช่นกัน ที่นั่นเรายังเขียนโปรแกรมสำหรับกระพริบ LED โดยใช้ไลบรารีนี้ ดังที่เราเห็นในรูปด้านล่าง คิวบ์จะสร้างไดรเวอร์ HAL และ CMSIS เรามาอธิบายไฟล์หลักที่ใช้กันดีกว่า:
- system_stm32f3x.c และ system_stm32f3x.h- จัดเตรียมชุดฟังก์ชันขั้นต่ำสำหรับการกำหนดค่าระบบจับเวลา
— core_cm4.h – ให้การเข้าถึงการลงทะเบียนของคอร์และอุปกรณ์ต่อพ่วง
- stm32f3x.h - ไฟล์ส่วนหัวของไมโครคอนโทรลเลอร์
— startup_system32f3x.s — รหัสเริ่มต้น มีตารางเวกเตอร์ขัดจังหวะ ฯลฯ
#รวม "main.h"
#รวม "stm32f3xx_hal.h"
เป็นโมฆะ SystemClock_Config (เป็นโมฆะ); /*ประกาศฟังก์ชั่นการกำหนดค่านาฬิกา*/
โมฆะคงที่ MX_GPIO_Init (เป็นโมฆะ); /*เริ่มต้น I/O*/
int main (เป็นโมฆะ) (
/*รีเซ็ตอุปกรณ์ต่อพ่วงทั้งหมด เริ่มต้นอินเทอร์เฟซ Flash และ Systick*/
HAL_Init();
/* ตั้งค่านาฬิการะบบ */
SystemClock_Config();
/* เริ่มต้นอุปกรณ์ต่อพ่วงที่กำหนดค่าไว้ทั้งหมด */
MX_GPIO_Init();
ในขณะที่ (1) (
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8); //เปลี่ยนสถานะของขา
HAL_ดีเลย์(100); )
}
เป็นโมฆะ SystemClock_Config (เป็นโมฆะ){
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
ถ้า (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK){
}
/**เตรียมใช้งานนาฬิกา CPU, AHB และ APB บัส */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
ถ้า (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){
_Error_Handler(__FILE__, __LINE__);
}
/**กำหนดค่าเวลาขัดจังหวะ Systick*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**กำหนดค่า Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn ขัดจังหวะการกำหนดค่า */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/** กำหนดค่าพินเป็นอินพุตเอาต์พุตแบบอะนาล็อก EVENT_OUT EXTI */
โมฆะคงที่ MX_GPIO_Init (เป็นโมฆะ){
GPIO_InitTypeDef GPIO_InitStruct;
/* เปิดใช้งานนาฬิกาพอร์ต GPIO */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*กำหนดค่าระดับเอาต์พุตพิน GPIO */
HAL_GPIO_WritePin (GPIOE, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*กำหนดค่าพิน GPIO: PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
เป็นโมฆะ _Error_Handler (ไฟล์ถ่าน *, บรรทัด int){
ในขณะที่ (1) (
}
}
#ifdef USE_FULL_ASSERT
โมฆะ assert_failed (ไฟล์ uint8_t*, บรรทัด uint32_t){
}
#เอ็นดิฟ
ที่นี่ เช่นเดียวกับในตัวอย่างก่อนหน้านี้ เราสามารถดูคำอธิบายของแต่ละฟังก์ชันในเอกสารประกอบได้ เป็นต้น คำอธิบายคู่มือผู้ใช้ UM1786 ของ STM32F3 HAL และไดรเวอร์โลว์เลเยอร์
เราสามารถสรุปได้ว่าตัวเลือกแรกที่ใช้ CMSIS นั้นยุ่งยากน้อยกว่า มีเอกสารประกอบสำหรับห้องสมุดแต่ละแห่ง ในโครงการต่อๆ ไป เราจะใช้ HAL และ CMSIS โดยใช้โปรแกรมกำหนดค่า STCube และหากเป็นไปได้ ให้ใช้รีจิสเตอร์โดยตรง โดยไม่ต้องใช้ชุดซอฟต์แวร์ วันนี้มาหยุดอยู่แค่นั้น ในบทความถัดไป เราจะดูหลักการพื้นฐานของการสร้างบ้านอัจฉริยะ ลาก่อนทุกคน.