เริ่มศึกษา STM32F103 เบื้องต้นกับ Keil กัน

Started by deejun, September 27, 2013, 10:46:32 AM

Previous topic - Next topic

deejun

ในครั้งนี้มาทำการเรียนรู้ STM32F103  กัน  ตัวอ้างอิงของผมเป็น STM32F103VBT6  ขนาดหน่วยความจำโปรแกรม  128K
ความถี่  72Mhz   ใครที่ใช้ เบอร์อื่นก็แก้ไขเล้กน้อยตามสเป็ค MCU แต่คำสั่งหลายๆอย่างคล้ายๆกันครับ

เริ่มแรกในบทนี้ก็เหมือนเดิม  ให้สร้าง Folderใหม่ขึ้นมา  ตั้งชื้อตามความต้องการของผู้ใช้ สมมุติในบทนี้ผมจะใช้ Clock
ผมสร้าง Floder ชื่อ Clock  และไปทำการก๊อปปี้  File ชื่อ system_stm32f10x.c กับ stm32f10x.h
เข้ามาไว้ใน Floder Clock ที่เร้าสร้างขึ้นมา  เวลาเราก๊อปปี้ ทั้งFloder ไปที่ไหน จะได้ไม่มีปัญหา หา File พวกนี้ไม่เจอ

system_stm32f10x.c  ก็อปมาได้จาก        C:\Keil\ARM\INC\ST\STM32F10x
stm32f10x.h               ก็อปมาได้จาก        C:\Keil\ARM\Startup\ST\STM32F10x

เมื่อมี 2 File นี้ก็เตรียมพร้อม สร้างโปรเจคได้เลย

เปิด Keil เลือกเบอร์ MCU ที่ท่านใช้   ในที่นี้เป็น  stm32f103vb  ครับ  ใครใช้นอกเหนือนี้ก็เปลี่ยนค่าเบอร์เอาครับ
เมื่อเลือกได้แล้ว  โปแกรมจะถามว่าให้แอดเอา startup_stm32f10x.s เข้ามาไว้ในFloder ด้วยมั๊ย  ตอบเลย Yes
ถ้าตอบ No ท่านจะต้องไปก็อปมาใหม่ใน C:\Keil\ARM\Startup\ST\STM32F10x มิเช่นนั้นจะใช้งานมิได้น่ะครับ

เมื่อทำการแอดเสร็จก็เป็นอันเตรียมตัวเขียนโปรแกรมต่อไป   ในช่วงที่จะเริ่มเขียนก็มีคำแนะนำอีกนึดนะครับว่า
STM3210x มันมีหลายซีเรีย จะแบ่งตามขนาดของหน่วยความจำ ซึ่งเราจะต้องรู้ด้วยว่า MCU ที่เราใช้เนี่ยอะ
มันเป็นซีเรียไหน  .......ก็ดูได้จาก Data sheet ของมันอะ  ดูตามต้นไม้  ปะแป้ง ก็ไม่เห็นเลข เอ้ยไม่เห็น รุ่น
น่ะครับ   มาถึงตรงนี้ใจเย็นๆ อย่าพึ่งถอนใจ  ว่ายุ่งยาก  ถ้าเริ่มสัปสนพัก 10 นาทีเดี๋ยวมาต่อกัน
แว๊ปผ่านไป 10 นาที ไวอย่างจรวจ น้ำ  เมื่อเริ่มไม่เข้าใจ หรือเข้าใจ ไม่เป็นไร  มาต่อกัน  ......................
ในรุ่นอ้างอิงผม  stm32f103vb ของผมเป็น MD มิเดียมคือค่าของหน่วยความจำขนาด กลางซึ่งในรุ่นF1 จะมีซีเรียดังนี้

STM32F10X_LD                  =               STM32 Low density devices
STM32F10X_LD_VL            =               STM32 Low density Value Line devices
STM32F10X_MD                 =               STM32 Medium density devices
STM32F10X_MD_VL           =               STM32 Medium density Value Line devices
STM32F10X_HD                 =               STM32 High density devices
STM32F10X_HD_VL           =               STM32 High density value line devices
STM32F10X_XL                  =               STM32 XL-density devices
STM32F10X_CL                  =               STM32 Connectivity line devices */

ดังนั้นมันมีความสำคัญม๊ากมากน่ะครับ เราจะต้องรู้ว่า MCUที่เราใช้เป็นรุ่นได 
stm32f103vbt6  นี้ตรงกับ    STM32F10X_MD  ครับ  เมื่อเรารู้แล้วก็จะให้กดคีย์  Alt+F7พร้อมกันครับ
กดเลยครับ ผมรู้ท่านยังไม่กด กดซะ เดี๋ยวเราจะไปต่อไม่ได้  อะไม่มีไรเกิดขึ้น......ก็เปิดหน้า Keil ก่อนกดครับ
เปิดหน้าเว๊ปนี้กดไม่มีอะไรเกิดขึ้นแน่ๆ  เมื่อเปิด Keil แล้วกด Alt+F7 จะเกิดบล็อกชื่อOption for targetขึ้นม
ให้เลือกหัวข้อชื่อ  C/C++ คลิ๊กเข้าไป จะเห็นมีบล็อกและช่องว่างๆและรายละเอียดขึ้นมา
ในช่องบนสุดแรกที่ชื่อ  Define  และทางขวามือเป็นช่องว่างๆสีขาวให้ใส่รุ่นของ MCU เข้าไปครับ
ในที่นี้เป็นพิมพ์ว     STM32F10X_MD ลงไปเป็นอันสร็จการเลือกรุ่น MCU ถ้าเป็นเบอร์อื่นให้ดูว่าเบอร์นั้นไปตกรุ่นไหน
ก็ใส่ชื่อรุ่นลงไปครับ

ส่วนค่าอื่นๆให้ศึกษาเอาจาก Web keil การใช้งาน หรือที่เคยอ้างอิงไว้หลายลิงค์ก่อนหน้านี้ใน STM32F4 ได้แนบไว้ถ้าไม่เข้าใจก็หา
ศึกษาเพิ่มการใช้ Keil  เพราะต่อจากนี้เราจะไม่พูดเรื่องการ Setup Keil แล้ว เราจะไปต่อที่ตัว MCU เลยครับ

เมื่อทำตามมาถึงตรงนี้เราก็พร้อมเดินเครื่องกันได้เลยครับ  ตรงนี้ขอจบไว้ก่อนที่การ  Setup Keil ก่อนเขียนโปรแกรม
 











deejun

มารู้จักการเซ็นอัป clock กันครับ
ก่อนอื่นต้องขอบอกไว้ก่อนว่าจริงๆแล้วใน system_stm32f10x.c เองได้กำหนดไว้แล้วว่า ที่ Xtal 8 Mhz นั้น CPU จะเซ็ทค่าที่ PLL9
ดังนั้นเราไม่จำเป็นต้อง setup clock ก็ได้  แต่ถ้าเราไม่ได้ใช้ xtal 8 Mhz อันนี้ละก็ จะต้องมาจัดการกับ clock ของระบบกันครับ

ในตัวอย่างนี้จะต่อกับหัวข้อข้างบนที่ได้บอกถึงการเซ็ทอัป Keil ไว้แล้ว ก็มาต่อกันเลยกับตัวอย่างที่ได้ทำไว้ รีจีสเตอร์ต่างๆก็ศึกษาได้ตาตัวอย่าง
ที่จะได้นำเสนอดังต่อไปนี้


#include"stm32f10x.h"

// Xtal 8Mhz   Pll*9  =  8*9  = 72Mhz

void  Clock()
                   {
                    RCC->CFGR      =   0;                                                 // Reset RCC_CFGR Register
                    RCC->CR        =   RCC_CR_HSEON;                           // Set External Xtal ON
                    while((RCC->CR & RCC_CR_HSIRDY)==0);                // Wait Xtal ON

                   /*    The Configuration of  Clock System    */
                   RCC->CFGR      =   RCC_CFGR_PLLSRC|RCC_CFGR_SW_PLL|RCC_CFGR_PPRE1_DIV2|
                   RCC_CFGR_ADCPRE_DIV6|RCC_CFGR_PLLMULL9;

                   /*    Enable PLLON   */                 
                   RCC->CR        |=  RCC_CR_PLLON;
                   while((RCC->CR & RCC_CR_PLLRDY)==0);
}

int main()
             {
              Clock();
}



deejun

เรียนรู้ GPIO ครับ
การใช้งาน  GPIO จะต้องศึกษา Register  GPIOx_CRL กับ GPIOx_CRH
GPIO bit0.......GPIO bit 7      ถูกควบคุมด้วย  GPIOx_CRL       เมื่อ  x คือ   A,B,C,D,E,F.G,H  = ชื่อPort
GPIO bit8.......GPIO bit 15    ถูกควบคุมด้วย  GPIOx_CRH       เมื่อ  x คือ   A,B,C,D,E,F.G,H  = ชื่อPort
ดังนั้นสังเกตุว่า  1 bit GPIO จะใช้ถึง   4 bit ของ Register Port ในการควบคุมว่า จะให้ bit ของตำแหน่งนั้นๆ ทำงาน
เป็นอะไร

เว็ปอ่านเพิ่ม   http://dics.voicecontrol.ro/dicsEE-IP/chapter/Setting%20GPIO%20manually

ใน 4 bit Register Port นั้นๆจะประกอบด้วย     ชื่อของbit นั้นๆ ดังนี้   MODE0  ,MODE1,CNF0,CNF1 
MODE0,MODE1 หลักๆ ใช้ในการกำหนดความเร็วของ Bit ขาที่อ้างอิง
CNF0,CNF1       ใช้ในการกำหนดทิศทางว่า จะให้ขานั้นๆเป็น Input ,Output, Funtion เป็นต้น
ในขณะที่เปิดไฟใหม่ๆ หรือไม่ได้กำหนดค่าไว้ก่อน  ค่าเริ่มต้นของมันจะเป็น GPIOx_CRL = 0x44444444
และ    GPIOx_CRH = 0x44444444  นั้นคือ ขาปล่อยลอยๆ ไม่รับ ไม่จ่าย กระแสไฟ


ตัวอย่าง ใช้ GPIOC Bit 6,Bit7,Bit8,Bit9  เป็น Output ขับที่ความถี่เร็วสุด   50Mhz



#include"stm32f10x.h"

void   delay(uint32_t num)
                                        {
                                         while(num--);     
}

void Clock()
                  {
                   RCC->CFGR      =     0;                                          // Reset RCC_CFGR Register
                   RCC->CR          =     RCC_CR_HSEON;                  // Set External Xtal ON
                   while((RCC->CR & RCC_CR_HSIRDY)==0);           // Wait Xtal ON

                   /* Configuration  Clock   */
                   RCC->CFGR      =   RCC_CFGR_PLLSRC|RCC_CFGR_SW_PLL|RCC_CFGR_PPRE1_DIV2|
                                                 RCC_CFGR_ADCPRE_DIV6|RCC_CFGR_PLLMULL9;
                 
                   /*    Enable PLLON   */
                   RCC->CR        |=  RCC_CR_PLLON;
                   while((RCC->CR & RCC_CR_PLLRDY)==0);
}
void    GPIO()
                   {
                     RCC->APB2ENR    =     RCC_APB2ENR_IOPCEN; //  เปิดคล็อกให้พ็อท C
                     GPIOC->CRL         =    0x33000000;   //  bit6, bit7
                     GPIOC->CRH        =    0x00000033;   //  bit8,bit9
                     GPIOC->ODR        =    0;
}
int main()
             {
              Clock();
              GPIO(); 
              while(1)
                         {
                          GPIOC->ODR  ^=  0x03C0;  //ไฟกระพริบ  ที่ GPIOC  Bit 6, Bit7,  Bit8,  Bit9 
                          delay(5000000);                  // ฟังก์ชันหน่วงเวลา
                         }
}






deejun

ลอง Over Clock    ,Under Clock ศึกษาดูความแตกต่างการทำงาน
จากตัวอย่าง GPIOก่อนหน้านี้ครับ

โวเวอร์คล็อก


#include"stm32f10x.h"

void   delay(uint32_t num)
                                        {
                                         while(num--);     
}

void Clock()
                  {
                   RCC->CFGR      =     0;                                          // Reset RCC_CFGR Register
                   RCC->CR          =     RCC_CR_HSEON;                  // Set External Xtal ON
                   while((RCC->CR & RCC_CR_HSIRDY)==0);           // Wait Xtal ON

                   /* Configuration  Clock   */
                   RCC->CFGR      =   RCC_CFGR_PLLSRC|RCC_CFGR_SW_PLL|RCC_CFGR_PPRE1_DIV2|
                                                 RCC_CFGR_ADCPRE_DIV6|RCC_CFGR_PLLMULL15;   //  [b]เปลี่ยนจาก PLL9 เป็น PLL15[/b]    8*14 =  112 Mhz           
                   /*    Enable PLLON   */
                   RCC->CR        |=  RCC_CR_PLLON;
                   while((RCC->CR & RCC_CR_PLLRDY)==0);
}
void    GPIO()
                   {
                     RCC->APB2ENR    =     RCC_APB2ENR_IOPCEN; //  เปิดคล็อกให้พ็อท C
                     GPIOC->CRL         =    0x33000000;   //  bit6, bit7
                     GPIOC->CRH        =    0x00000033;   //  bit8,bit9
                     GPIOC->ODR        =    0;
}
int main()
             {
              Clock();
              GPIO(); 
              while(1)
                         {
                          GPIOC->ODR  ^=  0x03C0;  //ไฟกระพริบ  ที่ GPIOC  Bit 6, Bit7,  Bit8,  Bit9 
                          delay(5000000);                  // ฟังก์ชันหน่วงเวลา
                         }
}




สังเกตุไฟกระพริบ ที่PLL15

อันเดอร์คล็อกถัดมาครับ


#include"stm32f10x.h"

void   delay(uint32_t num)
                                        {
                                         while(num--);     
}

void Clock()
                  {
                   RCC->CFGR      =     0;                                          // Reset RCC_CFGR Register
                   RCC->CR          =     RCC_CR_HSEON;                  // Set External Xtal ON
                   while((RCC->CR & RCC_CR_HSIRDY)==0);           // Wait Xtal ON

                   /* Configuration  Clock   */
                   RCC->CFGR      =   RCC_CFGR_PLLSRC|RCC_CFGR_SW_PLL|RCC_CFGR_PPRE1_DIV2|
                                                 RCC_CFGR_ADCPRE_DIV6|RCC_CFGR_PLLMULL3;  // เปลี่ยนค่า PLL  8*3=24Mhz
                 
                   /*    Enable PLLON   */
                   RCC->CR        |=  RCC_CR_PLLON;
                   while((RCC->CR & RCC_CR_PLLRDY)==0);
}
void    GPIO()
                   {
                     RCC->APB2ENR    =     RCC_APB2ENR_IOPCEN; //  เปิดคล็อกให้พ็อท C
                     GPIOC->CRL         =    0x33000000;   //  bit6, bit7
                     GPIOC->CRH        =    0x00000033;   //  bit8,bit9
                     GPIOC->ODR        =    0;
}
int main()
             {
              Clock();
              GPIO(); 
              while(1)
                         {
                          GPIOC->ODR  ^=  0x03C0;  //ไฟกระพริบ  ที่ GPIOC  Bit 6, Bit7,  Bit8,  Bit9 
                          delay(5000000);                  // ฟังก์ชันหน่วงเวลา
                         }
}




สังเกตุผลการเปลี่ยนแปลง

deejun

GPIO Input/Output

ใช้ GPIOE  bit 0,bit1,bit2,bit3  เป็น Input 


และใช้ GPIOC  bit6,bit7,bit8,bit9    เป็น Output



#include"stm32f10x.h"

void   delay(uint32_t num)
                                        {
                                         while(num--);     
}

void Clock()
                  {
                   RCC->CFGR      =     0;                                          // Reset RCC_CFGR Register
                   RCC->CR          =     RCC_CR_HSEON;                  // Set External Xtal ON
                   while((RCC->CR & RCC_CR_HSIRDY)==0);           // Wait Xtal ON

                   /* Configuration  Clock   */
                   RCC->CFGR      =   RCC_CFGR_PLLSRC|RCC_CFGR_SW_PLL|RCC_CFGR_PPRE1_DIV2|
                                                 RCC_CFGR_ADCPRE_DIV6|RCC_CFGR_PLLMULL9;
                 
                   /*    Enable PLLON   */
                   RCC->CR        |=  RCC_CR_PLLON;
                   while((RCC->CR & RCC_CR_PLLRDY)==0);
}
void    GPIO()
                   {
                     RCC->APB2ENR    =     RCC_APB2ENR_IOPCEN|RCC_APB2ENR_IOPEEN; //  เปิดคล็อกให้พ็อท C&E
                     GPIOC->CRL         =    0x33000000;   //  bit6, bit7
                     GPIOC->CRH        =    0x00000033;   //  bit8,bit9

                     GPIOE->CRL         =    0x00008888;   //  bit6, bit7

                     GPIOC->ODR        =    0;
}
int main()
             {
              Clock();
              GPIO(); 
              while(1)
                         {
                          if(GPIOE->IDR&0x01==1)              // ตรวจสอบ bit 0
                          GPIOC->ODR     |=   0x40; 
                          else
                          GPIOC->ODR     &=  FFBF;

                         if(GPIOE->IDR&0x02==1)              // ตรวจสอบ bit 1
                          GPIOC->ODR     |=   0x80; 
                          else
                          GPIOC->ODR     &=  FF7F;

                        if(GPIOE->IDR&0x04==1)              // ตรวจสอบ bit 2
                          GPIOC->ODR     |=   0x0100; 
                          else
                          GPIOC->ODR     &=  FEFF;

                         if(GPIOE->IDR&0x08==1)           // ตรวจสอบ bit 3
                          GPIOC->ODR     |=   0x0200; 
                          else
                          GPIOC->ODR     &=  FDFF;
                         }
}