0 Replies Latest reply on May 11, 2019 10:49 PM by MoTa_728816

    TSoC ADC to LED output (週末のLED)

    MoTa_728816

      IMG_3591_S.JPG

       

      それは昨日のこと、連休明け初の週末で呆けていると、

      どこぞの学生さんと思われる方からのご質問で

       

      It was the first weekend after the Golden Week, when I was busy dorking off,

      I found a question from (probably) a student of somewhere,

       

      「ADCでPoteniometerの値を読込んでLEDで表示する方法を教えておくれ」

      "Someone can help with this program about the potentiometer and ADC?"

       

      https://community.cypress.com/thread/46011

       

       

      という訳で、このくらいなら例によって ADC で読んで

      PWMのデューティー(compare)を変えてやって LED に出したら終わりじゃね?

      と、軽い気持ちで TSoC でプロジェクトを作って書き始めたところ、

      なんと TSoC の LED は PWM に繋がってない!という驚愕の事実に遭遇しました。

       

      Well, I thought, "it will be done just feeding an ADC value to a PWM which drives an output LED! A piece of cake!".

      And I started creating a project, but I was brown away when I noticed that the LED on TSoC can not be connected to a PWM!

       

       

      そこで「外付けでLEDを足してやったら何とかなるでしょ」と

      散歩がてら秋葉原で出かけて、買ってきました LED (^_^)V

       

      Then, "Well, I'll get a LED and connect it to a PWM pin of the board!",

      I made a round trip to Akihabara and got the LED (^_^)V (20 yen = 20 cents?)

       

      http://akizukidenshi.com/catalog/g/gI-11985/

       

       

      それで作ったのが(私視点でオーソドックスな)下記のプロジェクト (adc_test_190511)

       

      adc_test_190511 is the project I created in my orthodox approach.

       

      schematic

      002-blockdiagram.JPG

      001-schematic.JPG

      main.c

      =======================

      #include "project.h"

      #include "stdio.h"

       

      char str[128] ; /* print buffer */

      void print(char *str)

      {

          UART_UartPutString(str) ;

      }

       

      void init_hardware(void)

      {

          CyGlobalIntEnable; /* Enable global interrupts. */

          UART_Start() ;

          PWM_Start() ;

          ADC_Start() ;

      }

       

      void splash(void)

      {

          sprintf(str, "ADC -> PWM test (%s %s)\n", __DATE__, __TIME__) ;

          print(str) ;

      }

       

      float measure(void)

      {

          int16_t adc_count ;

          int16_t mV ;

          int     ch = 0 ;

       

          ADC_StartConvert() ;

          ADC_IsEndConversion(ADC_WAIT_FOR_RESULT) ;

          adc_count = ADC_GetResult16(ch) ;

          mV = ADC_CountsTo_mVolts(ch, adc_count) ;

          if (mV < 0) {

              mV = 0 ;

          }

          return( mV ) ;

      }

       

      int main(void)

      {

          uint16_t adc_ref_val = 3300 ;

          uint16_t mV = 0 ;

          uint16_t period = 10000 ;

          uint16_t compare = 0 ; /* pwm duty is compare / period */

       

          init_hardware() ;

       

          splash() ;

       

          PWM_WritePeriod(period) ;

       

          for(;;)

          {

              mV = measure() ;

              compare = (int)(period * mV / adc_ref_val) ; ;

              PWM_WriteCompare( compare ) ;

              sprintf(str, "POT = %d.%02d V\n", mV/1000, mV%1000) ;

              print(str) ;

              CyDelay(100) ;

          }

      }

      =======================

       

      TeraTerm-log

      010-TeraTerm-log.JPG

       

       

      で、これでどうよ?と回答したら、

      「UARTまだ習ってないし、私の簡単な方法で実現してくれない?」

      とハードルが上がったんだか、下がったんだか・・・

       

      so, I replied the thread with this project, "how about this?" then the response was

      "Ahh... I'm not learn about the UART yet, so... Can you help me with the simple way?"

      ... well, is he making the story easier or harder?

       

      彼のアプローチはループ毎にLEDを反転(点灯⇔消灯)させて、

      ADC の読取り値によってループの遅延時間を変えるというものでした。

       

      His approach was changing the delay in each loop according to the ADC value.

       

       

      私視点では「プログラム動作の安定性?なにそれおいしいの?」といったアプローチに感じたのですが、

      確かに、この方法であれば TSoC の LED でもADC の読取り値の変化を目視できると気付き、

      自分の頭の固さを反省しつつ下記のプロジェクトを作ってみました。(adc_test_190512)

       

      From my view point, "Changing the time of main loop each time? Sounds like a kludge!".

      But when I re-think about this, I noticed that actually with this approach, even with the TSoC LED we can view the changing of ADC value!

      So I regretted my hardheaded thought, I made a project (adc_test_190512)

       

      IMG_3593_S.JPG

       

      schamtic

      011-blockdiagram.JPG

      012-schematic.JPG

      main.c

      ================

      #include "project.h"

       

      int main(void)

      {

          int16_t adc_count ;

          int16_t mV = 0 ;

          int16_t ch = 0 ;

         

          CyGlobalIntEnable; /* Enable global interrupts. */

         

          ADC_Start() ;

         

          for(;;)

          {

              LED_Write(!LED_Read());

       

              ADC_StartConvert();

              ADC_IsEndConversion(ADC_WAIT_FOR_RESULT);

              adc_count = ADC_GetResult16(ch);

              mV = ADC_CountsTo_mVolts(ch, adc_count);

             

              CyDelay(mV/30);

          }

      }

      ================

       

      ADC の値によって LED の明るさが変わるのではなくて、点滅のスピードが

      まるでウル○ラマンのカ○ータイマーの様に変化する様を見ることができました。

       

      Now depending on the value of ADC, LED does not change the brightness, but the speed of blinking changes,

      just like the Color Timer of the Ult*aman.

       

      ところで、当初の課題には、

      「ADCのチャンネルを8bit, 100Hz サンプリングで攪乱して」

      という泣かせるセリフが書かれていました。

      (Confuse は Config の誤記なのでしょうが、ツボだったので残しておきます。)

       

      BTW, in the first question, there was an impressive sentence

      "Confuse an ADC of a channel, eight BITS, and 100 Hz sampling."

      (Confuse must be a typo of Config, but as I liked it, I quote ;-)

       

       

      後で考えてみると、課題の100Hzでサンプリングという話はどこかへ吹っ飛んでいってしまっていますので、

      この方法は課題の回答としては好ましくないのですね。

      ちなみに私の例も10Hzでサンプリングしていることになるので CyDelay(100) を CyDelay(10) にするか、

      他に Timer を設けて100Hz周期の処理にしてあげる必要がありました。

       

      Again, I noticed that I misplaced "100Hz sampling" during my trip to Akihabara.

      So the second project won't be a good answer for the exercise.

      Mine is also not good, as I inserted CyDelay(100) which makes the loop about 10Hz.

       

       

      という訳で、最初の回路図に Timer を増やして、100kHz のクロックを1000 回周期で回してあげれば 100Hz のサンプリングの ADC -> PWM 変換に

      なるよねといって作ったのが下記。(adc_test_190512B)

      (これは最初のものと同様に外付けのLEDが必要です。)

      流石に100Hz でプリント文を実行したら、いろいろとまずそうなので今回はUARTにはお引き取り願いました。

       

      So I made another project (adc_test_190512B) which utilizes a Counter driven by a 100kHz clock and set period to 1000.

      (This also requires an external LED, so my trip was not in vain ;-)

      Since printing ADC values 100 times per second does not sound cool, I asked the UART to leave.

       

      schematic

      021-schematic.JPG

      main.c

      =================

      #include "project.h"

      #include "stdio.h"

       

      volatile int pit_flag = 0 ;

       

      CY_ISR(pit_isr)

      {

          Timer_ClearInterrupt(Timer_INTR_MASK_TC) ;

          pit_flag = 1 ;

      }

       

      void init_hardware(void)

      {

          CyGlobalIntEnable; /* Enable global interrupts. */

          PWM_Start() ;

          ADC_Start() ;

          Timer_ClearInterrupt(Timer_INTR_MASK_TC) ;

          PIT_INT_ClearPending() ;

          PIT_INT_StartEx(pit_isr) ;

          Timer_Start() ;

      }

       

      float measure(void)

      {

          int16_t adc_count ;

          int16_t mV ;

          int     ch = 0 ;

       

          ADC_StartConvert() ;

          ADC_IsEndConversion(ADC_WAIT_FOR_RESULT) ;

          adc_count = ADC_GetResult16(ch) ;

          mV = ADC_CountsTo_mVolts(ch, adc_count) ;

          if (mV < 0) {

              mV = 0 ;

          }

          return( mV ) ;

      }

       

      int main(void)

      {

          uint16_t adc_ref_val = 3300 ;

          uint16_t mV = 0 ;

          uint16_t period = 1000 ;

          uint16_t compare = 0 ; /* pwm duty is compare / period */

       

          init_hardware() ;

       

          PWM_WritePeriod(period) ;

       

          for(;;)

          {

              if (pit_flag) {

                  pit_flag = 0 ;

                  mV = measure() ;

                  compare = (int)(period * mV / adc_ref_val) ; ;

                  PWM_WriteCompare( compare ) ;

              }

          }

      }

      =================

       

      このトピックを書いていたら、週末もすでに日曜日の午後になってしまいました。

      今日は「母の日」らしいので、何かお菓子でも買いに行かなくては予後が悪そうです。

      という訳で、今日はこの辺で (^_^)

       

      Writing this, it's already in the afternoon of Sunday.

      And since it's a mother's day in Japan, I need to go out and get some sweets for her.

      So let me call it a week ;-)

       

      moto