พฤศจิกายน 21, 2018, 01:53:20 pm *
ยินดีต้อนรับคุณ, บุคคลทั่วไป กรุณา เข้าสู่ระบบ หรือ ลงทะเบียน
ส่งอีเมล์ยืนยันการใช้งาน?

เข้าสู่ระบบด้วยชื่อผู้ใช้ รหัสผ่าน และระยะเวลาในเซสชั่น
   หน้าแรก   ช่วยเหลือ เข้าสู่ระบบ สมัครสมาชิก  
หน้า: [1]   ลงล่าง
  พิมพ์  
ผู้เขียน หัวข้อ: สอบถามการใช้งาน ADC ของบอร์ด STM32F4 Discovery หน่อยครับ  (อ่าน 14984 ครั้ง)
0 สมาชิก และ 1 บุคคลทั่วไป กำลังดูหัวข้อนี้
zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« เมื่อ: พฤศจิกายน 12, 2012, 12:35:42 am »

ผมเพิ่งลองใช้งาน mcu ตัวนี้ครับและก็มีเป้าหมายที่จะนำไปใช้ในการทำงานอยู่ จึงศึกษาไปเรื่อยๆ ตามหัวข้อที่ผมสนใจดังนี้
 - GPIO
 - External Interrupt
 - USART
 - Timer
 - Analog-to-Digital (ADC)

ซึ่งตอนนี้ก็ติดอยู่ที่ ADC นี่ล่ะครับ (ติดมา 3 วันเต็มๆละ - -") ปัญหาคือผมน่าจะยังไม่เข้าใจหลักการของมัน และก็ map กับ input port ทีรับสัญญาณไม่ถุก

ในตัวอย่างด้านล่างนี้ผมต่อสัญญาณ Analog เข้าที่ขา PA1 (ADC123_IN1) แต่เมื่อทำงานมันอ่านค่าได้ 0 ตลอด อยากขอคำแนะนำด้วยครับ

Code: (c)


#define ADC1_DR_ADDRESS    ((uint32_t)0x4001204C)
__IO uint16_t ADCConvertedValue = 0;
__IO uint32_t ADCConvertedVoltage = 0;

 .
 .
 .

/*************************************************************************
 * Function Name: InitADC1
 * Parameters: none
 * Return: none
 * Description: ADC Init subroutine
 *
 *************************************************************************/
void InitADC1(void)
{   
   ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
   
   //turn off dma
   DMA_Cmd(DMA2_Stream0, DISABLE);
   DMA_DeInit(DMA2_Stream0);
   ADC_DeInit();
   
  /* Enable peripheral clocks *************************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2| RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
   
   /* Configure ADC1 Channel pin as analog input ******************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* ADC1 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
   ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   ADC_InitStructure.ADC_NbrOfConversion = 1;

  ADC_Init(ADC1, &ADC_InitStructure);   
   
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);

  /* DMA2_Stream0 channel1 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_Channel_1; 
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
   
  /* DMA2_Stream0 enable */
  DMA_Cmd(DMA2_Stream0, ENABLE);

   /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
   ADC_Cmd(ADC1, ENABLE); //Enable ADC1
}

/**
   * @brief  Display ADC converted value on USART
   * @param  None
  * @retval None
   */
 void Display(void)
 {
    uint8_t text[50];
   
      ADCConvertedVoltage = ADCConvertedValue *3300/0xFFF;
 
   /*The ADC1 (PA1) pin is internally connected to a bridge divider by 2 */
   sprintf((char*)text,"ADC Value is  %d \r\n", ADCConvertedVoltage);
   
    USART_puts(USART1, text);   //send signal thougth USART
 }

 .
 .
 .

int main (void) {

   InitEXTIBtn();      // when press the button, it will call Display()

   InitADC1();
   /* Start ADC1 Software Conversion */
   ADC_SoftwareStartConv(ADC1);

        while(1){}
}




ขอบคุณครับ
บันทึกการเข้า
zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #1 เมื่อ: พฤศจิกายน 12, 2012, 01:37:30 am »

ตอนนี้ผมแก้ไขได้แล้วครับ เป็นเพราะความไม่เข้าใจในเรื่องของ DMA Stream และ Channel ของผมเอง   shy
บันทึกการเข้า
วิสิทธิ์ แผ้วกระโทก
Global Moderator
Sr. Member
*****
ออฟไลน์ ออฟไลน์

กระทู้: 307



| |
« ตอบ #2 เมื่อ: พฤศจิกายน 12, 2012, 08:15:41 am »

แทนที่จะให้ลบกระทู้ ช่วยมาอธิบายให้ท่านอื่นที่ยังไม่รู้ ได้รู้หน่อย ไม่ดีกว่าเหรอครับ  undecided
บันทึกการเข้า

zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #3 เมื่อ: พฤศจิกายน 12, 2012, 03:06:15 pm »

แทนที่จะให้ลบกระทู้ ช่วยมาอธิบายให้ท่านอื่นที่ยังไม่รู้ ได้รู้หน่อย ไม่ดีกว่าเหรอครับ  undecided

บางทีผมคิดว่ามันเป็นจุดพลาดเล็กๆของผมเอง  แต่ถ้าเผื่อมีใครอยากรู้ก็ได้เลยครับ จัดไป  cheesy

ผมจะอธิบายรวมในส่วนที่ศึกษามานะครับ
ในส่วนแรก เรื่องของการ setup project หรือพวกการ download ตั้งตั้ง library สามารถดูได้จาก http://www.electoday.com/bbs/viewthread.php?tid=19933

เมื่อทำการ set up โปรเจคได้แล้ว เนื่องจากผมใช้ Board STM32F4 Discovery มี External OSC อยู่ที่ 8 MHz จึงต้องไปแก้ไขในไฟล์ stm32f4xx.h บรรทัดที่ 98 จาก 25 MHz เป็น 8MHz
(ถ้าไฟล์มีการ set ค่าเป็น Read Only ให้ คลิกขวาที่ไฟล์และติ๊ก Read-Only ออก ก็จะแก้ไขได้ปกติ)

Code: (c)
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz (default is 25000000) */


ในไฟล์ New project ของบทความ http://www.electoday.com/bbs/viewthread.php?tid=19933 ได้กล่าวถึง การใช้งาน IO พื้นฐานไปแล้ว
ด้วยการสั่ง

GPIO_BitSet(GPIOD->ODR, GPIO_PIN);    // เพื่อ set ค่า logic ของ GPIO_PIN นั้นๆ ให้เป็น 1 (LED ที่ต้ออยู่จะติด)

หรือ

GPIO_BitRes(GPIOD->ODR, GPIO_PIN);    // เพื่อ set ค่า logic ของ GPIO_PIN นั้นๆ ให้เป็น 0 (LED ที่ต้ออยู่จะดับ)

ระบบที่ผมจะอธิบายเป็นตัวอย่างนี้มีการทำงานคือ
1. VR (Variable Resist.) ต่อเป็น Voltage Divide เพื่อป้อน Analog ให้ขา PA1 (ADC123_IN1) เมื่อหมุนเปลียนค่า LED จะติดเพิ่มขึ้นจาก 0V=0ดวง ไปจนสุดที่ 4 ดวง เมือลดค่า แรงดันลง ไฟจะค่อยๆ ดับลง ในทิศทางตรงข้าม
2. เมื่อกด User Button จะเกิดการ interrupt ส่งค่าของ ADC ที่อ่านได้ไปที่ USART1 ที่ต่อ TX ที่ขา PB6, RX ที่ขา PB7
3. เมื่อ ส่ง data ที่มีขนาด >= 12 ตัวอักษรจากภายนอกเข้ามาที่ Rx จะทำการ Interrupt และ Loop-back ส่ง data นั้นกลับไปทาง Tx


บันทึกการเข้า
zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #4 เมื่อ: พฤศจิกายน 12, 2012, 03:07:28 pm »

ต่อมาในเรื่องของ External Interrupt ต้องใช้งาน Nested Vectored Interrupt Controller (NVIC) กับการควบคุม clock พวก RCC

เริ่มแรก ตั้งค่าปุ่ม(สีฟ้า ซึ่งต่ออยู่ที่ PD0)เป็น input signal ก่อน
Code: (c)

#define USER_BUTTON   GPIO_Pin_0;

void initButton() {
    GPIO_InitTypeDef gpio;
   
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    GPIO_StructInit(&gpio);
    gpio.GPIO_Mode = GPIO_Mode_IN;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio.GPIO_Pin = USER_BUTTON;
    GPIO_Init(GPIOD, &gpio);
}


ต่อมา ตั้งค่าของการทำ EXTI โดยการ Set NVIC_IRQChannel ไปที่ EXTI0_IRQn เพื่อไปรอรับที่ Hanler ของเราด้านล่าง และ กำหนด Clock ของการ interrupt ของเราด้วย SysTick_Config
Code: (c)
void initExtInterrupt() {
    EXTI_InitTypeDef   EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);


    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void initClkInterrupt() {
    SysTick_Config(SystemCoreClock / 1000);
    NVIC_SetPriority(SysTick_IRQn, 1);
}


ต่อมาเป็นส่วนของ Handler ที่เข้ามารับการทำงานจากการ interrupt ในที่นี้ ผมให้มันส่ง msg ผ่าน USART ไปว่า Pushed และจากนั้นก็เรียก Func. Display() ที่ผมเขียนขึ้นมาเพื่อส่งค่า Analog ที่อ่านเข้ามาได้ (จะอธิบายต่อไป)
Code: (c)
void EXTI0_IRQHandler() {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
   
        USART_puts(USART1, "Pushed\r\n");   //send signal thougth USART
         
            Display();
      
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}


บันทึกการเข้า
zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #5 เมื่อ: พฤศจิกายน 12, 2012, 03:08:48 pm »

ดังนั้น ต่อมาก็พูดถึงเรื่องของ USART STM32F4 มี 6 ตัวให้เลือกใช้ด้วยกัน ในที่เลือกใช้ USART1 และกำหนด GPIO ที่เข้าเป็นขา PB6 สำหรับ TX และ PB7 สำหรับ RX และกำหนด USART_Mode = USART_Mode_Tx | USART_Mode_Rx เพื่อใช้ทั้งส่งและรับ โดยการรับเปิดใช้ งาน NVIC เพื่อ Interrupt ในการรับข้อมูล

Code: (c)
void init_USART1(uint32_t baudrate){
   
   GPIO_InitTypeDef GPIO_InitStructure; // this is for the GPIO pins used as TX and RX
   USART_InitTypeDef USART_InitStructure; // this is for the USART1 initilization
   NVIC_InitTypeDef NVIC_InitStructure; // this is used to configure the NVIC (nested vector interrupt controller)
   
   /* enable APB1 peripheral clock for USART1
    * note that only USART1 and USART6 are connected to APB2
    * the other USARTs are connected to APB1
    */
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
   
   /* enable the peripheral clock for the pins used by
    * USART1, PB6 for TX and PB7 for RX
    */
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
   
   /* This sequence sets up the TX and RX pins
    * so they work correctly with the USART1 peripheral
    */
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // Pins 6 (TX) and 7 (RX) are used
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;          // the pins are configured as alternate function so the USART peripheral has access to them
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      // this defines the IO speed and has nothing to do with the baudrate!
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;         // this defines the output type as push pull mode (as opposed to open drain)
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;         // this activates the pullup resistors on the IO pins
   GPIO_Init(GPIOB, &GPIO_InitStructure);               // now all the values are passed to the GPIO_Init() function which sets the GPIO registers
   
   /* The RX and TX pins are now connected to their AF
    * so that the USART1 can take over control of the
    * pins
    */
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
   
   /* Now the USART_InitStruct is used to define the
    * properties of USART1
    */
   USART_InitStructure.USART_BaudRate = baudrate;         // the baudrate
   USART_InitStructure.USART_WordLength = USART_WordLength_8b;// we want the data frame size to be 8 bits (standard)
   USART_InitStructure.USART_StopBits = USART_StopBits_1;      // we want 1 stop bit (standard)
   USART_InitStructure.USART_Parity = USART_Parity_No;      // we don't want a parity bit (standard)
   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
   USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // we want to enable the transmitter and the receiver
   USART_Init(USART1, &USART_InitStructure);               // again all the properties are passed to the USART_Init function which takes care of all the bit setting
   
   
   /* Here the USART1 receive interrupt is enabled
    * and the interrupt controller is configured
    * to jump to the USART1_IRQHandler() function
    * if the USART1 receive interrupt occurs
    */
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // enable the USART1 receive interrupt
   
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       // we want to configure the USART1 interrupts
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       // this sets the subpriority inside the group
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          // the USART1 interrupts are globally enabled
   NVIC_Init(&NVIC_InitStructure);                      // the properties are passed to the NVIC_Init function which takes care of the low level stuff   

   // finally this enables the complete USART1 peripheral
   USART_Cmd(USART1, ENABLE);
}


ฟังก์ชันต่อมา ใช้ในการส่งค่า String ที่เป็น char array ผ่านทาง USARTx ( USART ใดๆ ที่ต้องการ)
Code: (c)
/**
  * @brief  used to transmit a string of characters via the USART specified in USARTx.
  * @param  USARTx: can be any of the USARTs e.g. USART1, USART1 etc.
   *             *s: the string you want to send.
  * @retval None
  * Note: The string has to be passed to the function as a pointer because
  *        the compiler doesn't know the 'string' data type. In standard
  *        C a string is just an array of characters
  *
  * Note 2: At the moment it takes a volatile char because the received_string variable
  *          declared as volatile char --> otherwise the compiler will spit out warnings
  */
void USART_puts(USART_TypeDef* USARTx, volatile char *s){

   while(*s){
      // wait until data register is empty
      while( !(USARTx->SR & 0x00000040) );
      USART_SendData(USARTx, *s);
      *s++;
   }
}



ส่วนต่อมาคือ interrupt request handler (IRQ) สำหรับ USART1 interrupts (ทำการ loop back data กลับไป)
Code: (c)
void USART1_IRQHandler(void){
   
   // check if the USART1 receive interrupt flag was set
   if( USART_GetITStatus(USART1, USART_IT_RXNE) ){
      
      static uint8_t cnt = 0; // this counter is used to determine the string length
      char t = USART1->DR; // the character from the USART1 data register is saved in t
      
      /* check if the received character is not the LF character (used to determine end of string)
       * or the if the maximum string length has been been reached
       */
      if( (t != '\n') && (cnt < MAX_STRLEN) ){
         received_string[cnt] = t;
         cnt++;
      }
      else{ // otherwise reset the character counter and print the received string
         cnt = 0;
         USART_puts(USART1, received_string);
      }
   }
}


บันทึกการเข้า
zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #6 เมื่อ: พฤศจิกายน 12, 2012, 03:10:17 pm »

ส่วนสุดท้าย ส่วนของ Analog-Digital Conversion (ADC)
ฟังก์ชัน ด้านล่างใช้กำหนดค่าของ ADC1 ซึ่งเราจะนำค่าที่ได้โดยตรงจาก Memory จึงใช้ DMA(Directed Memory Access) โดย ADC1 นั้นจะเก็บข้อมูลไว้ที่ DMA2 stream0 Channel0 (สามารถดูเรื่องของ DMA Controller ได้ที่ http://armvn-repo.googlecode.com/files/STM32F4-Technical-Training.pdf หน้า 64) ซึ่งรับข้อมูลที่เป็น Analog ได้ที่ระดับ 0V - VDDA ซื่อง VDDA มีค่า 3 V (จาก Schematic ของบอร์ด)  จากฟังก์ชันนี้เราจะได้ค่า output มาเก็บไว้ที่ ADCConvertedValue ซึ่งผมกำหนดให้ ADC_ContinuousConvMode = ENABLE; ซึ่งทำให้ทำการ Conversion ค่า ADC ไปเรื่อยๆ รายละเอียดเกี่ยวกับ ADC มีผู้เขียนไว้ในนี้ครับ http://www.electoday.com/home/space.php?uid=79&do=blog&id=177 (STM32F1 คล้ายๆกันครับ เอา Concept ละกัน)
Code: (c)
#define ADC1_DR_ADDRESS    ((uint32_t)0x4001204C)
__IO uint16_t ADCConvertedValue = 0;
__IO uint32_t ADCConvertedVoltage = 0;

void InitADC1(void)
{   
   ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
   
   //turn off dma
   DMA_Cmd(DMA2_Stream0, DISABLE);
   DMA_DeInit(DMA2_Stream0);
   ADC_DeInit();
   
  /* Enable peripheral clocks *************************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2| RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
   
   /* Configure ADC1 Channel pin as analog input ******************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* ADC1 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   ADC_InitStructure.ADC_NbrOfConversion = 1;

  ADC_Init(ADC1, &ADC_InitStructure);   
   
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);

  /* DMA2_Stream0 channel1 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
   
  /* DMA2_Stream0 enable */
  DMA_Cmd(DMA2_Stream0, ENABLE);

   /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
   ADC_Cmd(ADC1, ENABLE); //Enable ADC1
}


ต่อมา นี่คือส่วนของการแสดงค่าผ่าน USART ที่ผมใช้เรียกตอน External Interrupt ครับ
Code: (c)
void Display(void)
{
   uint8_t text[50];

   ADCConvertedVoltage = ADCConvertedValue *100/0xFFF;

   sprintf((char*)text,"ADC Value is  %d \r\n", ADCConvertedVoltage);
 
   USART_puts(USART1, text);   //send signal thougth USART
}


บันทึกการเข้า
zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #7 เมื่อ: พฤศจิกายน 12, 2012, 03:11:35 pm »

และนี่คือ Code ทั้งหมดครับ
Code: (c)
#include "stm32f4xx.h"
#include "Peripheral_Config.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_adc.h"
#include "misc.h"

#define Bit_Set(A, B)        (A |= (0x01<<(B)))
#define Bit_Res(A, B)        (A &= ~(0x01<<(B)))
#define Bit_Test(A, B)        ((A) & (0x01<<(B)))
#define Toggle(A,B)               (A ^= (0x01<<(B)))
#define GPIO_BitSet(A, B)      (A |= B)
#define GPIO_BitRes(A, B)      (A &= ~B)
#define GPIO_BitToggle(A, B)(A ^= B)
#define GPIO_ReadPin(A,B)      (A &= B)
#define ON   1
#define OFF   0
#define USER_BUTTON   GPIO_Pin_0;
#define Green      GPIO_Pin_12
#define Orange   GPIO_Pin_13
#define Red         GPIO_Pin_14
#define Blue      GPIO_Pin_15
#define LED(A,B)   (B==ON) ? GPIO_BitSet(GPIOD->ODR, A) : GPIO_BitRes(GPIOD->ODR, A)

#define MAX_STRLEN 12 // this is the maximum string length of our string in characters
volatile char received_string[MAX_STRLEN+1]; // this will hold the recieved string

#define ADC1_DR_ADDRESS    ((uint32_t)0x4001204C)
__IO uint16_t ADCConvertedValue = 0;
__IO uint32_t ADCConvertedVoltage = 0;

static __IO uint32_t TimingDelay;

/*********** Function Prototype ******************************/
void TimingDelay_Decrement(void);
void Delay(__IO uint32_t nTime);
void delay(uint32_t ms);
void init_USART1(uint32_t baudrate);
void USART_puts(USART_TypeDef* USARTx, volatile char *s);
void initButton(void);
void initExtInterrupt(void);
void initClkInterrupt(void);
void InitADC1(void);
void init(void);
void Display(void);
void DMA_Config(void);
void ADCInit(void);
/*************************************************************/


int main(void) {

   Peripheral_MCU_Config();
   
   init();   

   USART_puts(USART1, "Init complete! Hello World!\r\n");

  while (1)
  {      
      ADCConvertedVoltage = ADCConvertedValue *100/0xFFF;
      
      if ( ADCConvertedVoltage <= 5 )
      {
         LED(Green, OFF);
         LED(Blue, OFF);
         LED(Red, OFF);
         LED(Orange, OFF);
      }
      else if ( ADCConvertedVoltage <= 25 )
      {
         LED(Green, ON);
         LED(Blue, OFF);
         LED(Red, OFF);
         LED(Orange, OFF);
      }
      else if ( ADCConvertedVoltage <= 50 )
      {
         LED(Green, ON);
         LED(Blue, ON);
         LED(Red, OFF);
         LED(Orange, OFF);
      }
      else if ( ADCConvertedVoltage <= 75 )
      {
         LED(Green, ON);
         LED(Blue, ON);
         LED(Red, ON);
         LED(Orange, OFF);
      }
      else
      {
         LED(Green, ON);
         LED(Blue, ON);
         LED(Red, ON);
         LED(Orange, ON);
      }      
   }
}


void init() {
   initButton();
   initExtInterrupt();
   initClkInterrupt();
   init_USART1(9600);
   InitADC1();
   /* Start ADC1 Software Conversion */
   ADC_SoftwareStartConv(ADC1);

}


/**
  * @brief  initializes the USART1 peripheral.
  * @param  baudrate: the baudrate at which the USART is supposed to operate.
  * @retval None
  */
void init_USART1(uint32_t baudrate){
   
   GPIO_InitTypeDef GPIO_InitStructure; // this is for the GPIO pins used as TX and RX
   USART_InitTypeDef USART_InitStructure; // this is for the USART1 initilization
   NVIC_InitTypeDef NVIC_InitStructure; // this is used to configure the NVIC (nested vector interrupt controller)
   
   /* enable APB1 peripheral clock for USART1
    * note that only USART1 and USART6 are connected to APB2
    * the other USARTs are connected to APB1
    */
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
   
   /* enable the peripheral clock for the pins used by
    * USART1, PB6 for TX and PB7 for RX
    */
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
   
   /* This sequence sets up the TX and RX pins
    * so they work correctly with the USART1 peripheral
    */
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // Pins 6 (TX) and 7 (RX) are used
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;          // the pins are configured as alternate function so the USART peripheral has access to them
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;      // this defines the IO speed and has nothing to do with the baudrate!
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;         // this defines the output type as push pull mode (as opposed to open drain)
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;         // this activates the pullup resistors on the IO pins
   GPIO_Init(GPIOB, &GPIO_InitStructure);               // now all the values are passed to the GPIO_Init() function which sets the GPIO registers
   
   /* The RX and TX pins are now connected to their AF
    * so that the USART1 can take over control of the
    * pins
    */
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
   
   /* Now the USART_InitStruct is used to define the
    * properties of USART1
    */
   USART_InitStructure.USART_BaudRate = baudrate;         // the baudrate
   USART_InitStructure.USART_WordLength = USART_WordLength_8b;// we want the data frame size to be 8 bits (standard)
   USART_InitStructure.USART_StopBits = USART_StopBits_1;      // we want 1 stop bit (standard)
   USART_InitStructure.USART_Parity = USART_Parity_No;      // we don't want a parity bit (standard)
   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
   USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // we want to enable the transmitter and the receiver
   USART_Init(USART1, &USART_InitStructure);               // again all the properties are passed to the USART_Init function which takes care of all the bit setting
   
   
   /* Here the USART1 receive interrupt is enabled
    * and the interrupt controller is configured
    * to jump to the USART1_IRQHandler() function
    * if the USART1 receive interrupt occurs
    */
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // enable the USART1 receive interrupt
   
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       // we want to configure the USART1 interrupts
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       // this sets the subpriority inside the group
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          // the USART1 interrupts are globally enabled
   NVIC_Init(&NVIC_InitStructure);                      // the properties are passed to the NVIC_Init function which takes care of the low level stuff   

   // finally this enables the complete USART1 peripheral
   USART_Cmd(USART1, ENABLE);
}


/**
  * @brief  used to transmit a string of characters via the USART specified in USARTx.
  * @param  USARTx: can be any of the USARTs e.g. USART1, USART1 etc.
   *             *s: the string you want to send.
  * @retval None
  * Note: The string has to be passed to the function as a pointer because
  *        the compiler doesn't know the 'string' data type. In standard
  *        C a string is just an array of characters
  *
  * Note 2: At the moment it takes a volatile char because the received_string variable
  *          declared as volatile char --> otherwise the compiler will spit out warnings
  */
void USART_puts(USART_TypeDef* USARTx, volatile char *s){

   while(*s){
      // wait until data register is empty
      while( !(USARTx->SR & 0x00000040) );
      USART_SendData(USARTx, *s);
      *s++;
   }
}


// this is the interrupt request handler (IRQ) for ALL USART1 interrupts
void USART1_IRQHandler(void){
   
   // check if the USART1 receive interrupt flag was set
   if( USART_GetITStatus(USART1, USART_IT_RXNE) ){
      
      static uint8_t cnt = 0; // this counter is used to determine the string length
      char t = USART1->DR; // the character from the USART1 data register is saved in t
      
      /* check if the received character is not the LF character (used to determine end of string)
       * or the if the maximum string length has been been reached
       */
      if( (t != '\n') && (cnt < MAX_STRLEN) ){
         received_string[cnt] = t;
         cnt++;
      }
      else{ // otherwise reset the character counter and print the received string
         cnt = 0;
         USART_puts(USART1, received_string);
      }
   }
}


void initButton() {
    GPIO_InitTypeDef gpio;
   
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    GPIO_StructInit(&gpio);
    gpio.GPIO_Mode = GPIO_Mode_IN;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio.GPIO_Pin = USER_BUTTON;
    GPIO_Init(GPIOD, &gpio);
}

void initExtInterrupt() {
    EXTI_InitTypeDef   EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);


    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void initClkInterrupt() {
    SysTick_Config(SystemCoreClock / 1000);
    NVIC_SetPriority(SysTick_IRQn, 1);
}

void EXTI0_IRQHandler() {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
   
        USART_puts(USART1, "Pushed\r\n");   //send signal thougth USART
         
            Display();
      
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}


/*************************************************************************
 * Function Name: InitADC1
 * Parameters: none
 * Return: none
 *
 * Description: ADC Init subroutine
 *
 *************************************************************************/
void InitADC1(void)
{   
   ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
   
   //turn off dma
   DMA_Cmd(DMA2_Stream0, DISABLE);
   DMA_DeInit(DMA2_Stream0);
   ADC_DeInit();
   
  /* Enable peripheral clocks *************************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2| RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
   
   /* Configure ADC1 Channel pin as analog input ******************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* ADC1 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   ADC_InitStructure.ADC_NbrOfConversion = 1;

  ADC_Init(ADC1, &ADC_InitStructure);   
   
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);

  /* DMA2_Stream0 channel1 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
   
  /* DMA2_Stream0 enable */
  DMA_Cmd(DMA2_Stream0, ENABLE);

   /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
   ADC_Cmd(ADC1, ENABLE); //Enable ADC1
}


/**
   * @brief  Display ADC converted value on USART
   * @param  None
  * @retval None
   */
void Display(void)
{
   uint8_t text[50];

   ADCConvertedVoltage = ADCConvertedValue *100/0xFFF;

   sprintf((char*)text,"ADC Value is  %d \r\n", ADCConvertedVoltage);
 
   USART_puts(USART1, text);   //send signal thougth USART
}

void delay(uint32_t ms) {
    ms *= 3360;
    while(ms--) {
        __NOP();
    }
}

void Delay(__IO uint32_t nTime)
{
  TimingDelay = nTime;
 
  while(TimingDelay != 0);
}

/**
  * @brief  Decrements the TimingDelay variable.
  */
void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  {
    TimingDelay--;
  }
}


ใครกำลังศึกษา STM32F4 พูดคุยกันได้นะครับ ขอให้ทุกคนโชคดี  grin
บันทึกการเข้า
วิสิทธิ์ แผ้วกระโทก
Global Moderator
Sr. Member
*****
ออฟไลน์ ออฟไลน์

กระทู้: 307



| |
« ตอบ #8 เมื่อ: พฤศจิกายน 12, 2012, 03:37:32 pm »

กำลังคิดจะซื้อเหมือนกันครับ แต่ยังไม่รู้จะเอามาทำงานแนวไหน

่ช่วยยกตัวอย่าง งาน ที่เอามาทำหน่อยได้ไหมครับ

สำหรับข้อมูลที่อธิบายมาก มีประโยชน์มากๆ ครับ สำหรับเพื่อนๆ ในบอร์ด และผู้ที่อาจมีปัญหาอยู่

ดีครับ ช่วยๆ แบ่งปันความรู้กันครับ มีแต่ผลดี ไม่มีผลเสียครับ

 kiss kiss kiss
บันทึกการเข้า

zamurais
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 8


| |
« ตอบ #9 เมื่อ: พฤศจิกายน 14, 2012, 12:11:57 pm »

จาก Features (http://www.st.com/internet/evalboard/product252419.jsp) ของตัวบอร์ดมันแล้ว ค่อนข้างมีประสิทธิภาพสูง และราคาถูก
ทีนี้มันก็ขึ้นอยู่กับว่าแล้วแต่คนไหนจะเอาไปทำอะไร แต่ feature ที่ผมเห็นน่าสนคือ DSP, accelerometer, และ motion sensor  cheesy

ส่วนตัวผมไม่ได้คิดอะไรมาก เพราะมีบอร์ดนี้อยู่ในกรุเลยนำออกมาใช้ครับ  smiley
ผมเอามาทำเป็น Energy Meter สำหรับ smart plug ครับ เพื่อเก็บค่าพลังงาน ส่งเข้าไปยัง Concentrator เข้า server อีกทีหนึ่ง
บันทึกการเข้า
วิสิทธิ์ แผ้วกระโทก
Global Moderator
Sr. Member
*****
ออฟไลน์ ออฟไลน์

กระทู้: 307



| |
« ตอบ #10 เมื่อ: พฤศจิกายน 14, 2012, 12:43:11 pm »

อ้างถึง
Energy Meter

ตัวนี้ ผมก็สนใจเหมือนกัน สนใจมานานแหละ แต่ ยังไม่ได้เริ่มเลย  cry
บันทึกการเข้า

nacksina
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 1


| |
« ตอบ #11 เมื่อ: เมษายน 17, 2013, 11:53:58 am »

ใช้โปรแกรมอะไรหรอครับ  แล้วก็ตอนนี้ผมใช้ Atollic Truestudio แล้วเกิดปัญหา
มัน error 
ขึ้นว่า fatal error: Peripheral_Config.h: No such file or directory
ต้องทำยังไงอะครับ

ขอบคุนครับบ
บันทึกการเข้า
ShadowMan
Administrator
Hero Member
*****
ออฟไลน์ ออฟไลน์

เพศ: ชาย
กระทู้: 8272


ShadowWares


| |
« ตอบ #12 เมื่อ: เมษายน 17, 2013, 01:22:15 pm »

อ้างถึง
fatal error: Peripheral_Config.h: No such file or directory
ยังหาไฟล์ Peripheral_Config.h ไม่เจอ ให้ตรวจสอบการกำหนดรายละเอียดต่างๆ ของ Project (ทำอย่างไร ให้อ่านจากคู่มือของเครื่องมือตัวที่ใช้)
บันทึกการเข้า

By SDW: Do No Wrong Is Do Nothing
          If you want to increase your success rate, double your failure rate
chirawat
Jr. Member
**
ออฟไลน์ ออฟไลน์

กระทู้: 54


| |
« ตอบ #13 เมื่อ: พฤษภาคม 23, 2013, 04:06:47 pm »

ขอบคุณมากครับ เป็นประโยชน์มากๆ
บันทึกการเข้า
pisit1234
Newbie
*
ออฟไลน์ ออฟไลน์

กระทู้: 1


| |
« ตอบ #14 เมื่อ: มิถุนายน 18, 2013, 04:09:11 pm »

ขอบคุณมากคราบบบบ cheesy
บันทึกการเข้า
หน้า: [1]   ขึ้นบน
  พิมพ์  
 
กระโดดไป: