มีใครเคยแสดงค่าการ Interrupt บนจอ LCD บ้างครับ

  • 13 Replies
  • 3614 Views
ท่าน Takkykun ครับ เห็นท่านถามมาหลายกระทู้แล้ว
ทุกๆท่านๆ ที่ตอบ เขาแสดง Concept ของแนวความคิดนะครับ ว่าสิ่งที่ท่านถามมีแนวทางแนะนำว่าควรทำอย่างไร ?
ถ้าเป็นรายละเอียดเรื่อง Code แนะนำให้ศึกษาเพิ่มเติมและพยายามก่อนจะดีกว่าครับ
ทำแบบนี้จะเป็นประโยชน์ต่อตัวท่านเองมากกว่า เพราะประสบการณ์เหล่านี้ท่านจะได้ด้วยตนเอง
และหากจะ share ความรู้หรือประสบการณ์ที่ท่านได้ รวมถึงความผิดพลาดที่ได้ทำ และคิดว่าเป็นประโยชน์ต่อส่วนรวม ก็ลองแสดงความเห็นได้ครับ
แต่หากติดขัดจริงๆ (ไม่ใช่แบบเบื้องต้นนักนะ มันแสดงถึงความไม่พยายามมาก่อน ) ค่อยลงคำถามต่อ จะดีกว่าครับ
"Stay Hungry, Stay Foolish"
จงกระหาย และ ทำตัวโง่ให้ตลอดเวลา
"Innovation distinguishes between a leader and a follower."
นวัตกรรมแยกผู้นำกับผู้ตามออกจากกัน

คนฉลาด...ต้องโง่เป็น คนโง่ไม่เป็น...จะไม่มีทางฉลาด

ตอนนี้ผมกำลังศึกษาเรื่องของ TIM อยู่เลยครับ (ผมมือใหม่หัดเล่นครับ เพิ่งมาเขียนจริงๆ จังๆ แค่เดือนเดียวนี่เอง) ตอนนี้อยากทราบว่า การทำงานของ TIM นั้นเป็นการกำหนดสัญญาณพัลส์เพื่อทำการทริกการทำงาน ถูกไหมครับ แล้วทีนี้ผมต้องการนำสัญญาณทริกนั้นไปกำกับการทำงานของ ADC อยากทราบว่า ถ้าสมมติผมตั้งค่า TIM3 ดังคำสั่งนี้

uint16_t PrescalerValue = 0;

/**********************************************************************************************************************/
void TIM3_Configuration(void)
/**********************************************************************************************************************/
{

   
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
   TIM_OCInitTypeDef  TIM_OCInitStructure;
   
  /* Compute the prescaler value */
  PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 6000000) - 1;

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 20;
  TIM_TimeBaseStructure.TIM_Prescaler = 167;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  /* Prescaler configuration */
  TIM_PrescalerConfig(TIM3, PrescalerValue, TIM_PSCReloadMode_Immediate);

  /* Output Compare Timing Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 10;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
   

  /* Output Compare Timing Mode configuration: Channel2 */
  /*TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);

  /* Output Compare Timing Mode configuration: Channel3 */
  /*TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

  TIM_OC3Init(TIM3, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);

  /* Output Compare Timing Mode configuration: Channel4 */
  /*TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

  TIM_OC4Init(TIM3, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);
   
  /* TIM Interrupts enable */
  TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);

  /* TIM3 enable counter */
  TIM_Cmd(TIM3, ENABLE);
   
    /* Connect TIM3 pins to AF2 */ 
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_TIM3);
   


}

อยากทราบว่า

1. พัลส์ของ Channel ไหนที่จะไปทริกการทำงานของ ADC ครับ
2. NVIC ต้องตั้งค่าเพื่อกำกับ TIM3 แล้วต้องตั้งค่าเพื่อกำกับ ADC และ DMA ด้วยหรือเปล่าครับ
3. ผมต้องการนับสัญญาณการทริกจาก TIM3 ไม่ทราบว่าจะมีวิธีการอย่างไรครับ เนื่องจากฟังก์ชั่น TIM ไม่ใช่ลูปของ Interrupt จึงไม่สามารถใส่ตัวแปรเพื่อทำการนับค่า count ในนั้นได้ ทีนี้ไม่ทราบว่าหากผมทำการส่งสัญญาณ Pulse ไปที่พอร์ตๆ หนึ่ง แล้วนับจังหวะที่พอร์ตนั้นส่งออกสัญญาณ pulse ซึ่งจะมีค่า logic == 1 และทำการตรวจจับโลจิคนั้นเป็นการ count หนึ่งค่า ไม่ทราบว่าพอจะเป็นไปได้ไหมครับ เพราะผมกลัวว่าการทำงานนับค่า count ซึ่งอยู่ใน main loop นั้น จะไม่ทันสัญญาณการทริก

ขอบคุณครับ

*

Offline pa_ul

  • ***
  • 247
    • View Profile
>1. พัลส์ของ Channel ไหนที่จะไปทริกการทำงานของ ADC ครับ

channel ของ ADC ที่ต้องการใช้ถูกกำหนดด้วย EXTSEL, JEXTSEL ไม่ได้อยู่ที่การตั้งค่า Timer3

>2. NVIC ต้องตั้งค่าเพื่อกำกับ TIM3 แล้วต้องตั้งค่าเพื่อกำกับ ADC และ DMA ด้วยหรือเปล่าครับ

ใช้ หรือไม่ใช้ก็ได้ อยู่ที่ความต้องการ

>3. ผมต้องการนับสัญญาณการทริกจาก TIM3 ไม่ทราบว่าจะมีวิธีการอย่างไรครับ

งงกับคำถาม ?? ถ้าตั้งให้มันทำงาน 10 ครั้งต่อวินาที มันก็เกิดขึ้น 10 ครึ้งต่อวินาที ไม่มีทางเป็นอย่างอื่นอยู่แล้ว

> เนื่องจากฟังก์ชั่น TIM ไม่ใช่ลูปของ Interrupt จึงไม่สามารถใส่ตัวแปรเพื่อทำการนับค่า count ในนั้นได้

ไปนับตรงจุดที่รับรู้การทำงานของ TIMER สิครับ

> ทีนี้ไม่ทราบว่าหากผมทำการส่งสัญญาณ Pulse ไปที่พอร์ตๆ หนึ่ง แล้วนับจังหวะที่พอร์ตนั้นส่งออกสัญญาณ pulse ซึ่งจะมีค่า logic == 1 และทำการตรวจจับโลจิคนั้นเป็นการ count
> หนึ่งค่า ไม่ทราบว่าพอจะเป็นไปได้ไหมครับ เพราะผมกลัวว่าการทำงานนับค่า count ซึ่งอยู่ใน main loop นั้น จะไม่ทันสัญญาณการทริก

ทำได้ถ้ารู้ว่าจะเอาโค้ดที่สั่งให้พอร์ตทำงานไปใส่ไว้ที่ไหน แต่ถ้ารู้ว่าจะใส่ไว้ตรงไหน ก็ไม่น่าจะมีคำถามข้อ 2 และ 3 ก่อนหน้านี้

ถามจริงๆเถอะ ว่าห่วงอะไรกับจำนวนการทริกในตอนนี้ ทั้งๆที่ยังไม่สามารถจะจัดการให้ TIMER3 ทริกให้ ADC ทำงานได้สำเร็จเลย ถ้าจัดการให้มันทำงานได้หนึ่งครั้ง แล้วจะปรับให้มันเป็นกี่ครั้งก็ไม่ใช่เรื่องยากเย็นอะไร
 

ต้องการหาค่า RMS ของสัญญาณ Sine ความถี่ 50 Hz ใช่มั้ยครับ
ตอนนี้อย่าเพิ่งไปสนใจ สัญญาณ Input ครับ เอาเป็นว่า Config ยังไงให้ ADC ใช้งานได้ก่อน
Interrupt ยังไม่ต้องใช้ครับ เอา Polling ให้รอดก่อน
เริ่มจาก กำหนด CLK ให้ ADC ก่อนครับ
   RCC_ADCCLKConfig(RCC_PCLK2_Div6);
เสร็จแล้วก็ Enable Clock ให้กับ ADC และ PORT ซะ
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
Config Port ให้เป็น Analog Input
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

Config ค่าต่างๆให้ ADC
   ADC_InitStructure.ADC_Mode = ADC_Mode_Independent
   ADC_InitStructure.ADC_ScanConvMode = DISABLE;
   ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
   ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   ADC_InitStructure.ADC_NbrOfChannel = 1;
   ADC_Init(ADC1, &ADC_InitStructure);
   ADC_Cmd(ADC1, ENABLE);
   ADC_ResetCalibration(ADC1);
   while(ADC_GetResetCalibrationStatus(ADC1));
   ADC_StartCalibration(ADC1);
   while(ADC_GetCalibrationStatus(ADC1));

แล้วก็ลองอ่านค่า ADC มาโชว์ดูครับ โชว์ข้อมูลดิบๆก่อน ลองหา R ปรับค่าได้ มาลองต่อ เป็น Voltage Divider ดูก่อน
   While(1)
   {
      ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_239Cycles5);
      ADC_SoftwareStartConvCmd(ADC1, ENABLE);
      while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
      ADC_RAW_Value = ADC_GetConversionValue(ADC1);
   }

LCD SHOW ทุก 20us ไม่ได้ครับ มันเร็วไปจนตามนุษย์จับไม่ทัด
ผมมีตัวอย่างคร่าวๆในการนำไปประยุตได้บ้างลองศึกาดูครับ
ต้องการที่แซมปิ้ง 20uS ไปแก้เวลาที่ Tim3->PSC  และ Tim3->ARR ครับ จัดให้เวลาเท่ากับ 20uS
ตัวอย่างเก็บค่าแค่ 2500ค่า ระวังเรืองสเต๊กพอยเตอร์ให้ดีครับ  ศึกษาการดึงค่าและจัดเก็บให้ดีๆ จะพลาดกันง่ายๆ

#include"stm32f10x.h"
int bn[2500];
int in = 0;

void delay_ms(unsigned int in)
                             {
                              unsigned int jn,kn;
                              for(jn=0;jn<in;jn++)
                              for(kn=0;kn<6000;kn++);                                                                                                                 
                             }
void sys_clock()
                {
                 RCC->CFGR     =    0;
                 RCC->CR       =    RCC_CR_HSION;
                 while((RCC->CR & RCC_CR_HSIRDY)==0);       
                 RCC->CR       |=   RCC_CR_HSEON;
                   while((RCC->CR & RCC_CR_HSERDY)==0);
                  RCC->CFGR     =    RCC_CFGR_SW_PLL|RCC_CFGR_PPRE1_DIV2|RCC_CFGR_ADCPRE_DIV6|
                     RCC_CFGR_PLLSRC|RCC_CFGR_PLLMULL9;
                   RCC->CR       |=   RCC_CR_PLLON;
                   while((RCC->CR & RCC_CR_PLLRDY)==0);       
                  }   
void ADC()
           {
                //ADC configuration
               RCC->APB2ENR   =  RCC_APB2ENR_ADC1EN;   
                ADC1->CR1      =  ADC_CR1_SCAN;
                ADC1->CR2      =  ADC_CR2_ADON;   
                ADC1->CR2      |=  ADC_CR2_EXTSEL|ADC_CR2_SWSTART|ADC_CR2_EXTTRIG|ADC_CR2_CAL;//
           while((ADC1->CR2 & ADC_CR2_CAL) != 0x00);/* Check the end of ADC1 calibration */
                ADC1->SMPR1    =  0;        // 1.5 cycles conversion time
               ADC1->SQR3     =  14;     //channel number 14 PC4 first conversion
                }
void Time()
           {
            // Timer 3 counter
                 RCC->APB1ENR |=    RCC_APB1ENR_TIM3EN;
                  TIM3->PSC    =     500;         // Set prescaler  (PSC + 1)
                  TIM3->ARR    =     50;           // Auto reload value 50
                  TIM3->DIER   =     TIM_DIER_UIE; // Enable update interrupt (timer level)
                  TIM3->CR1    =     TIM_CR1_CEN;   // Enable timer

           }   
void ADC_Count()
                {
                         if(in<2500)
                                        {
                                          ADC1->CR2 |= ADC_CR2_SWSTART|ADC_CR2_ADON;/* Start ADC1 Software Conversion */   
                                          while((ADC1->SR & ADC_SR_EOC )==0)
                                          ADC1->SR   =   0;
                                          bn[in] =  ADC1->DR;
                                          in = in+1;
                                        }
               else
               TIM3->CR1    =     0;   // Stop timer End Tim3   

                 }               
                        
int main()
             {
               sys_clock(); // Initial clock
               ADC();// Initial ADC CH 14
          Time();               
                        
            
               while (1)
                        {
                            /*     code program  LCD show   
                                      if(in>=2500)
                                               {
                                                 code RMS  2500 Point
                                                 code program  LCD show
                                                }
                                    goto keep 2500 Point new Or End Program
                              */   
                            
                  }
             }



void TIM3_IRQHandler()
           {
            TIM3->SR  =  0;   
               ADC_Count();
           }

*

Offline firmware.c

  • *****
  • 181
  • Firmware Design
    • View Profile
อย่างที่บอกครับ LCD ควรใช้ main software ในการควบคุม interrupt จับค่า sampling ใส่ buffer แล้วนำมาให้ main ทำการ display
IAR Embedded Workbench for ARM
AVR-Studio + AVR-GCC
CodeBlocks + MinGw
CodeBlocks + Gtk+