2011년9월23일_ARM_AT91SAM7S256 PWM제어기를 사용하여 LED의 밝기를 조절하자.




● pwm.c   PWM초기화와 실행 중 듀티비조정

   1: void PWM3_INIT(void)        //PWM 채널3 초기화 PA14 - 장치B
   2: {
   3:     PMC_PCER = (1 << PWMC);        // PWM전력공급
   4:     PIOA_PUDR = (1 << PWM3);        // 풀업저항제거
   5:     PIOA_BSR = (1 << PWM3);        //장치B모드 사용
   6:     PIOA_PDR = (1 << PWM3);        // 병렬I/O기능 OFF    
   7:     PWM_MR = (3 << PREA) | (30 << DIVA) | (3 << PREB) | (30 << DIVB);    // MCK / 8 / 30 = 200kHz
   8:     PWM_CMR3 = (0 << CPD) | (0 << CPOL) | (0 << CALG) | (11 << CPRE);    // clkA선택, 듀티비조정, H레벨시작, 톱니파s
   9:     PWM_CDTY3 = 100;    // 듀티비 100, High시간 100
  10:     PWM_CPRD3 = PEROID;    // 최대값 800, Low 시간 800 - 100 = 700,
  11:     PWM_ENA = (1 << CHID3);        // PWM 3번 채널 동작
  12:  
  13:     return ;
  14: }
  15:  
  16: void PWM3_DutySet(unsigned int uiDuty)
  17: {
  18:  
  19:     if(800 < uiDuty)
  20:     {
  21:         uiDuty = 800;
  22:     }
  23:     else if(0 >= uiDuty)
  24:     {
  25:         uiDuty = 1;     }
  26:     
  27:     PWM_CUPD3 = uiDuty;
  28:     
  29:     return ;
  30: }



● main.c  하이퍼터미널로 방향키 입력받아 LED에 연결된 PWM출력 듀티비조정하여 LED밝기 조정

   1: // PWM초기화와 설정 마무리와 실행 중 PWM duty가변
   2: // 2011.09.23 - 수만
   3:  
   4: #include "pio.h"
   5: #include "dbgu.h"
   6: #include "lcd.h"
   7: #include "led.h"
   8: #include "aic.h"
   9: #include "timer.h"
  10: #include "ultra.h"
  11: #include "adc.h"
  12: #include "UserFunc.h"
  13: #include "pwm.h"
  14:  
  15: #define    ESCAPEKEY        27
  16: #define    CUTVAL            500
  17:  
  18: void ALL_INIT()
  19: {
  20:     LCD_INIT();
  21:     LED_INIT();
  22:     DBGU_INIT();
  23:     ADC_INIT();
  24:     PWM3_INIT();
  25: }
  26:  
  27: int main(void)
  28: {
  29:     int iResult = 0;
  30:     unsigned char ucRData;
  31:     unsigned char ucFlagUpdate = 0;
  32:     short usPWM3_Duty = 100;
  33:  
  34:     ALL_INIT();
  35:  
  36:     Send_String("test PWM\n\r");
  37:     LCD_String("test PWM");
  38:  
  39:     while(1)
  40:     {    
  41:         ucRData = Recv_Char();
  42:         if(ESCAPEKEY == ucRData) 
  43:         {
  44:             // 방향키는 이스케이프문자 27 + 65 66 67 68이나 이상하게 안됨. -> 두 번 더 읽어야 됨.
  45:             ucRData = Recv_Char();
  46:             ucRData = Recv_Char();
  47:  
  48:             switch(ucRData)
  49:             {
  50:                 case 66:    //방향키 ↓
  51:                     if(0 < usPWM3_Duty)
  52:                     {
  53:                         usPWM3_Duty = usPWM3_Duty - 50;
  54:                         ucFlagUpdate = 1;
  55:                     }
  56:                     break;
  57:  
  58:                 case 65:    // 방향키 ↑
  59:                     if(800 > usPWM3_Duty)
  60:                     {
  61:                         usPWM3_Duty = usPWM3_Duty + 50;
  62:                         ucFlagUpdate = 1;
  63:                     }
  64:                     break;
  65:  
  66:                 default:
  67:                     ucFlagUpdate = 0;
  68:                     break;
  69:             }    
  70:  
  71:         /*    // 광센서 입력 받아 PWM duty cycle 조정
  72:             // 1. 데이터 획득
  73:             iResult = ADC_RUN7_int();        // 밝으면 1000 어두우면 600
  74: 
  75:             // 2. 전처리
  76:             iResult = iResult - CUTVAL;        // 밝으면 500 어두우면 100
  77:             if(0 > iResult)        //result가 음수이면 안됨
  78:             {
  79:                 iResult = 0;
  80:             }
  81: 
  82:             // 3. 시간cal    
  83:             usPWM3_Duty = PEROID - (iResult * 3) / 2;    //iResult는 0 ~ 523사이의 값을 가짐. 1.5배를 해 감도를 높임
  84:                                                     // 밝으면 LED 파워↓, 어두우면 LED 파워↑
  85:             ucFlagUpdate = 1;         // LCD와 하이퍼터미널에 표시
  86:         */
  87:             if(1 == ucFlagUpdate)
  88:             {
  89:                 PWM3_DutySet(usPWM3_Duty);
  90:                 LCD_Cursor(1, 0);
  91:                 printf_LCD("duty = %d", usPWM3_Duty, 0, 0);
  92:                 printf_DBGU("PWM duty = %d\n", usPWM3_Duty, 0, 0);
  93:             }
  94:         }
  95:     }
  96:     
  97:     return 0;
  98: }
  99:  


//소스설명추가


문제점은 PWM_CUPD3레지스터의 값을 100에서 0으로 바꾸고 다시 증가시키면 LED가 최대로 밝아진다.
PWM_CUPD3레지스터의 값을 계속 증가시키면 LED의 밝기는 어두워지고,
레지스터의 값이 800인 최대값이 되었다가 다시 감소하면 정상동작으로 돌아온다. (감소하면 LED의 밝기 어두워짐)
이 문제가 발생하는 원인이 무엇인지 알지 못 하여 임시적으로 PWM_CUPD3레지스터의 값이 0이 되지 못 하게 막았다.





DSCN4442 DSCN4443DSCN4444
 DSCN4440DSCN4445 

듀티비를 점점 올려서 찍은 사진..LED의 밝기가 점점 밝아진다. 
디지털은 1과 0 (ON과 OFF)밖에 할 수 없으나 PWM을 사용하면 이렇게 중간값처럼 보이게 할 수 있다.


 








참조(Reference)


DSCN4460 DSCN4461