การเขียนโปรแกรม STM32F4 การสร้างโครงการใหม่ใน Keil STM32F407(STM32F4-DISCOVERY) - วิธีการที่ไม่ได้มาตรฐาน - ไลบรารี่มาตรฐานตอนที่ 1

จนถึงจุดนี้ เราได้ใช้ไลบรารีเคอร์เนลมาตรฐาน - CMSIS ในการกำหนดค่าพอร์ตให้เป็นโหมดการทำงานที่ต้องการ เราต้องค้นหารีจิสเตอร์ที่รับผิดชอบฟังก์ชันบางอย่าง และค้นหาข้อมูลอื่นๆ ที่เกี่ยวข้องกับกระบวนการนี้ในเอกสารขนาดใหญ่ด้วย สิ่งต่างๆ จะเจ็บปวดและเป็นกิจวัตรมากขึ้นเมื่อเราเริ่มทำงานโดยใช้เครื่องจับเวลาหรือ ADC จำนวนรีจิสเตอร์มีมากกว่าพอร์ต I/O มาก การกำหนดค่าด้วยตนเองใช้เวลานานและเพิ่มโอกาสที่จะเกิดข้อผิดพลาด ดังนั้นหลายคนจึงชอบทำงานกับไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน - StdPeriph มันให้อะไร? ง่ายมาก - ระดับของนามธรรมจะเพิ่มขึ้น คุณไม่จำเป็นต้องเข้าไปดูเอกสารประกอบและคิดถึงการลงทะเบียนเป็นส่วนใหญ่ ในไลบรารีนี้ โหมดการทำงานและพารามิเตอร์ทั้งหมดของขอบ MK ได้รับการอธิบายไว้ในรูปแบบของโครงสร้าง ตอนนี้ ในการกำหนดค่าอุปกรณ์ต่อพ่วง คุณจะต้องเรียกใช้ฟังก์ชันการเริ่มต้นอุปกรณ์ด้วยโครงสร้างที่เติมเต็มเท่านั้น

ด้านล่างนี้เป็นรูปภาพที่มีการแสดงแผนผังของระดับของสิ่งที่เป็นนามธรรม

เราทำงานร่วมกับ CMSIS (ซึ่ง "ใกล้เคียงที่สุด" กับแกนกลาง) เพื่อแสดงให้เห็นว่าไมโครคอนโทรลเลอร์ทำงานอย่างไร ขั้นตอนต่อไปคือไลบรารีมาตรฐาน ซึ่งเราจะเรียนรู้วิธีใช้งานทันที ถัดมาเป็นไดรเวอร์อุปกรณ์ เข้าใจว่าเป็นไฟล์ *.c \ *.h ที่มีอินเทอร์เฟซซอฟต์แวร์ที่สะดวกสำหรับการควบคุมอุปกรณ์ใด ๆ ตัวอย่างเช่น ในหลักสูตรนี้ เราจะจัดเตรียมไดรเวอร์สำหรับชิป max7219 และโมดูล esp8266 WiFi ให้กับคุณ

โครงการมาตรฐานจะรวมไฟล์ต่อไปนี้:


ก่อนอื่นแน่นอนว่าไฟล์เหล่านี้เป็นไฟล์ 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-B

9 - ดีบักเกอร์ 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 และหากเป็นไปได้ ให้ใช้รีจิสเตอร์โดยตรง โดยไม่ต้องใช้ชุดซอฟต์แวร์ วันนี้มาหยุดอยู่แค่นั้น ในบทความถัดไป เราจะดูหลักการพื้นฐานของการสร้างบ้านอัจฉริยะ ลาก่อนทุกคน.