PWM을 사용한 사인 신호 생성


16

MC68HC908GP32 마이크로 컨트롤러를 사용하여 사인 신호를 올바르게 생성 할 수 없습니다 . PWM 설명은 349 페이지에서 시작합니다. 클록 주파수는 2.4MHz이며, 프리스케일러를 사용하고 다음과 같이 타이머 모듈러스를 350으로 설정하여 7kHz PWM을 사용했습니다.

T1SC = 0x60;    // Prescaler: Div entre 64
//Counter modulo = 0x015E = 350
T1MODH = 0x01;   // High
T1MODL = 0x5E;   // Low

PWM 출력은 다음 RLC 필터로 필터링 한 다음 직렬 1uF 캡을 사용하여 DC를 제거합니다. 차단 주파수는 PWM의 7kHz보다 낮습니다.

여기에 이미지 설명을 입력하십시오

먼저 LUT를 사용해 보았습니다. LUT는이 사이트를 사용하여 생성 된 샘플입니다 (100 개 샘플, 진폭 = 250). 이것은 단일 기간으로 구성됩니다.

 int seno[100]={ 125, 133, 141, 148, 156, 164, 171, 178, 185, 192, 198, 205, 211, 216, 221, 226, 231, 235, 238, 241, 244, 246, 248, 249, 250, 250, 250, 249, 248, 246, 244, 241, 238, 235, 231, 226, 221, 216, 211, 205, 198, 192, 185, 178, 171, 164, 156, 148, 141, 133, 125, 117, 109, 102, 94, 86, 79, 72, 65, 58, 52, 45, 39, 34, 29, 24, 19, 15, 12, 9, 6, 4, 2, 1, 0, 0, 0, 1, 2, 4, 6, 9, 12, 15, 19, 24, 29, 34, 39, 45, 52, 58, 65, 72, 79, 86, 94, 102, 109, 117}; 

다음 펄스의 폭은 PWM주기마다 계산됩니다.

interrupt 4 void rsi_t1ch0 (void)
{
    //-- disable interruption flag
    T1SC0&=(~0x80);
    //-- pwm to '0' 
    PTB&=0xFD;

    //some sensor measures are done here.... 100 out of the 350 cycles are left for this                
}
/************************************************************/
/* TIM1 overflow rutine                                     */
/************************************************************/
interrupt 6 void rsi_ov1 (void)
{

    T1SC&=(~0x80);
    //-- set PWM to 1
    PTB|=0x02;
    T1CH0H = ((seno[fase])>>8);   // high bits
    T1CH0L = (seno[fase])&0xFF;   // low bits
    fase+=1;
    if (fase >= 99)
      fase=0;
}

void main(void)
{
float temp;
    int i;

    CONFIG1|=0x01;  
    DDRB=0xFF;      //-- Port B is set as output
    PTB=0x00;       
    //Timer setup
    T1SC = 0x60;    // Prescaler: Div by 64  
    T1MODH = 0x01;   //Counter modulo
    T1MODL = 0x5E;  
    T1SC0 = 0x50;  //Comparator setup
    //-- Initial width
    T1CH0H = 0x00;
    T1CH0L = 0x53;

    EnableInterrupts;
    T1SC&=~(0x20); //Run timer forever
    for(;;);   
}

스코프에 꽂으면 다음 신호가 나타납니다. 우리는 최소한의 이상한 피크를 피할 수 없습니다.

여기에 이미지 설명을 입력하십시오

이 피크를 확대 / 축소 할 때 PWM 출력 (위)이 실제로 어떻게 잘못되었는지 확인할 수 있습니다.

여기에 이미지 설명을 입력하십시오

따라서 한동안 어지럽히고 그것을 제거 할 수없는 후에, 우리는 각 샘플의 값을 하드 코딩하는 대신 MCU에서 사인 신호를 계산하려고 시도했습니다. 모든 카운터 설정 직전에 주요 기능에 다음 코드를 추가했습니다.

 for(i=0;i<99;i++) {
     temp=100*(sin(2*3.14159*i/100)+1);
     seno[i]=(int)temp;
 }

그러나 결과는 정현파처럼 보이지 않습니다.

여기에 이미지 설명을 입력하십시오

몇 시간 동안 어려움을 겪은 후에도 실수를 찾지 못했습니다. 조언을 부탁드립니다.


전체 PWM 값 목록을 게시 할 수 있습니까?
pjc50

@ pjc50 여기 있습니다 : pastebin.com/sNyA0Hki . 대단히 감사합니다.
Serge

중간의 모든 "0"값을 "1"로 바꾸십시오. 나는 0이 원하는 낮은 신호보다는 넓은 높은 신호를 제공한다고 생각합니다.
pjc50

@Serge-데이터를 인라인하십시오. 페이스트가 사라질 수 있으며 질문의 일부를 푸는 것이 나쁩니다. 그러나 공간을 많이 사용하지 않도록 형식을 지정하십시오. 감사.
Trygve Laugstøl

그것은 분명히 필터가 아닙니다-행운을 빕니다-테이블이 손상되었거나 포인터를 잃어 버린 것 같습니다.
Andy aka

답변:


16

마이크로 컨트롤러 데이터 시트의 350 페이지 하단에, 오버 플로우 인터럽트 동안 타이머 값 레지스터에 작은 값을 쓰면 다음 pwm 반복에서만 다음 인터럽트가 트리거 될 수 있습니다. 인터럽트 루틴이 실행 중입니다.

펄스 폭 값을 변경하기 위해 TIM 채널 레지스터에 동기화되지 않은 쓰기는 최대 2 개의 PWM주기 동안 오작동을 일으킬 수 있습니다. 예를 들어, 카운터가 이전 값에 도달하기 전에 새 값을 쓰지만 카운터가 새 값에 도달 한 후에는 PWM 기간 동안 비교할 수 없습니다. 또한 TIM 오버 플로우 인터럽트 루틴을 사용하여 더 작은 새로운 펄스 폭 값을 작성하면 비교가 누락 될 수 있습니다. TIM은 새 값을 작성하기 전에 전달할 수 있습니다.

이것은 pwm 값이 전체 pwm 클럭주기 + 타이머 길이 (주변 길이에 따라)처럼 보이는 전체 시간 동안 높게 유지된다는 사실에 의해 확인됩니다. 타이머 길이 레지스터에 기록되는 값은 오류 발생 시점에 0에 가까운 것일 수 있으므로 인터럽트 중에 카운터가 더 작은 값을 통과하여 다음 사이클에서만 트리거되는 것이 가능합니다.

이는 정현파 최소 레벨을 ISR을 실행하는 데 걸리는 시간보다 높은 레벨로 늘리거나 새 레벨을 설정하는 메커니즘을 변경하여 해결할 수 있습니다. 이 작업을 수행하는 방법은 페이지 351의 맨 위에 나와 있습니다.


1
데이터 시트를 읽을 때 어떻게 건너 뛸 수 있는지 모르겠습니다. 감사합니다!
Serge
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.