原文出自枯葉之碟的博客
一.輸出比較初始化 步驟: 1.復(fù)用端口映射為OCx 例如:RPA0Rbits.RPA0R=0b0101; 即RPA0引腳作為外設(shè)OC1使用 見(jiàn)附一 2.OCM<2:0>:輸出比較模式選擇位 例如:OC1CON=0X06; //輸出比較端口1配置為PWM故障禁止模式。 3.OC32<5>:32 位比較模式位 例如:OC1CONCLR=0X010; //將第五位清零,設(shè)置為16位單定時(shí)器模式。 4.OCTSEL<3>:輸出比較定時(shí)器選擇位 例如:OC1CONSET=0X08; //將第三位設(shè)置為一,選擇定時(shí)器3為基時(shí)鐘 5.定時(shí)器使能初始化 例如:OpenTimer3(T1_ON|T1_SOURCE_INT|T1_PS_1_1,pwmn); Pwmn周期數(shù)={ FB外設(shè)/pwmfp頻率 } - 1; 6.ON<15>:輸出比較外設(shè)使能位 例如:OC1CONSET=0X8000; //將第15位置一,輸出比較使能。 二.中斷觸發(fā)條件 單比較模式 ?? 比較匹配事件強(qiáng)制OCx 引腳為高電平;該引腳的初始狀態(tài)為低電平。在發(fā)生單比較匹配事件 時(shí),產(chǎn)生中斷。 ?? 比較匹配事件強(qiáng)制OCx 引腳為低電平;該引腳的初始狀態(tài)為高電平。在發(fā)生單比較匹配事件時(shí),產(chǎn)生中斷。 ?? 比較匹配事件使OCx 引腳電平翻轉(zhuǎn)。翻轉(zhuǎn)事件是連續(xù)的,且每次翻轉(zhuǎn)事件都會(huì)產(chǎn)生一次中斷。 雙比較模式 當(dāng)OCx引腳被驅(qū)動(dòng)為低電平(單脈沖的下降沿)時(shí),相應(yīng)通道的中斷標(biāo)志OCxIF會(huì)置為有效。 PWM模式 TyIF 中斷標(biāo)志在每個(gè)PWM 周期邊界處置為有效。 當(dāng)使能了具有故障保護(hù)輸入模式的PWM 時(shí),必須通過(guò)將相應(yīng)的TRIS SFR 位置1 以將OCFx 故 障引腳配置為輸入。選擇PWM 故障模式時(shí), OCFx 故障輸入引腳不會(huì)自動(dòng)配置為輸入。 三.計(jì)算各項(xiàng)值 所需的PWM通過(guò)寫(xiě)入OCxRS 寄存器來(lái)指定PWM 占空比。可以在任何時(shí)候?qū)慜CxRS 寄存器,但是在PRy和TMRy 發(fā)生匹配(即周期結(jié)束)前占空比值不會(huì)被鎖存到OCxR 中。 PWM 周期 = [(PR 1) ?? TPB ?? (TMR 預(yù)分頻值)] 或T=PR 1/(Fpb/PS) PWM 頻率 = 1/[PWM 周期] 最大PWM 分辨率:在一個(gè)PWM周期內(nèi)有n個(gè)時(shí)基(PR),為2的x次方,分辨率為x。 以頻率為52.08 kHz為例 FPB = 10 MHz Timer2 預(yù)分頻比設(shè)置: 1:1 1/52.08 kHz = (PR2 1) ?? TPB ?? (Timer2 預(yù)分頻值)=(PR2 1)/(FPB/Timer2預(yù)分頻) 19.20 us = (PR2 1) ?? 0.1 us ?? (1) PR2 = 191 確定可用于52.08 kHz PWM 頻率和10 MHz 外設(shè)總線時(shí)鐘速率的占空比的最大分辨率。 1/52.08 kHz = 2^PWM 分辨率?? 1/10 MHz ?? 1 19.20 us = 2^PWM 分辨率?? 100 ns ?? 1 192 = 2^PWM 分辨率 log10(192) = (PWM 分辨率) ?? log10(2) PWM 分辨率 = 7.6 位 四.拓展 #用PWM繪制新波形 峰峰值最大為PR定時(shí)器數(shù)。 每個(gè)PWM周期為一個(gè)樣本 所需波形頻率: 所需頻率=1/(n個(gè)樣本*PWM周期) 每個(gè)樣本波形的幅度值(占空比*PR): 波形/n,將n個(gè)值列入數(shù)組表格,OCxRS引用。 每個(gè)PWM周期輸出通過(guò)RC濾波電路轉(zhuǎn)換為模擬信號(hào),約為一條幅值為 高電平*占空比 的直線, 通過(guò)改變占空比控制賦值y軸,再通過(guò)控制周期數(shù)控制產(chǎn)生的x軸 正弦波波形產(chǎn)生,占空比計(jì)算值 OC1RS=偏移量 振幅*SIN(2*pi/周期樣本值),但如此短的時(shí)間無(wú)法 來(lái)的及計(jì)算sin,最好制成表格數(shù)組引用。 #發(fā)出聲音 繪制相應(yīng)的頻率可發(fā)出相應(yīng)的音高(do,re,me…),再調(diào)整波形幅度決定音色(不同的樂(lè)器)。 舉例說(shuō)明 一. 用PWM制作呼吸燈效果 #include #pragma config FPLLIDIV = DIV_2 // PLL Input Divider (2x Divider) #pragma config FPLLMUL = MUL_24 #pragma config FPLLODIV = DIV_2 #pragma config FPBDIV = DIV_1 #pragma config FNOSC = FRCPLL #pragma config FUSBIDIO = OFF #pragma config FWDTEN = OFF #pragma config JTAGEN = OFF int pwm1,pwmn,pwmfp,count,pwm_g; void PWMinint() { OC1CON=0; //關(guān)閉 初始都為零,定時(shí)器二,16位模式 OC1CON=0x06; //PWM無(wú)故障模式 OC1R=10000; //初始占空比為10000 OC1RS=10000; pwmn=48000000/pwmfp-1; PWM周期數(shù) OpenTimer2(T2_ON|T2_SOURCE_INT|T2_PS_1_1,pwmn); //初始定時(shí)器2 OC1CONSET=0x8000; //開(kāi)啟輸出比較使能 } void __ISR(_TIMER_2_VECTOR,ipl3) Timer2hander(void) //中斷 { mT2ClearIntFlag(); if(pwm_g==0) count ; //當(dāng)count越大亮度越低反之詳見(jiàn)電路圖 else count--; if(count>4410) pwm_g=1; if(count==0) pwm_g=0; OC1RS=count*pwmn/4410; //4410/4410=1s一翻轉(zhuǎn) } int main() { RPB7Rbits.RPB7R=0b0101; pwmfp=4410; PWMinint(); mT2SetIntPriority(3); mT2IntEnable(1); INTEnableSystemMultiVectoredInt(); while(1); } 二.按鍵實(shí)時(shí)控制PWM #include // Configuration Bit settings // SYSCLK = 48 MHz (8MHz Crystal / FPLLIDIV * FPLLMUL / FPLLODIV) // PBCLK = 48 MHz (SYSCLK / FPBDIV) // Primary Osc w/PLL (XT ,HS ,EC PLL) // WDT OFF #pragma config FPLLMUL = MUL_24, FPLLIDIV = DIV_2, FPLLODIV = DIV_2, FWDTEN = OFF #pragma config POSCMOD = OFF, FNOSC = FRCPLL, FPBDIV = DIV_1,FSOSCEN = OFF #pragma config FUSBIDIO = OFF //FUSBIDIO????? #pragma config FVBUSONIO = OFF #pragma config JTAGEN = OFF //JTAG disable #pragma config CP = OFF #pragma config DEBUG = ON // Period needed for timer 1 to trigger an interrupt every 0.1 second // (48MHz PBCLK / 1 = 48000000KHz Timer 1 clock) #define PERIOD 48000 //48000/48000000 = 0.001s = 1ms #define BTN_DELAY 5 //2*1=2ms #define SYS_FREQ (48000000L) //???????? typedef enum //PRO_Status { SHOW_PERIOD = 0, SHOW_DUTY, SHOW_SET_PERIOD, SHOW_SET_DUTY, SET_PERIOD, SET_DUTY }PRO_STATUS; PRO_STATUS g_status=SHOW_PERIOD; UINT16 g_period=40,g_duty=20; //初始周期40,占空比20 UINT16 g_set_period=40,g_set_duty=20; int g_led_cnt=0,g_led_flag=0,g_btn_cnt=0,g_btn_flag=0,flag=0; //顯示于按鍵標(biāo)志,用于周期性定時(shí)處理LED顯示和按鍵 unsigned char Led_lib[] = { 0x42, 0xf3, 0x86, 0xa2, 0x33, 0x2a, 0x0a, 0xf2, 0x02, 0x22, //0-9 0x40, 0xf1, 0x84, 0xa0, 0x31, 0x28, 0x08, 0xf0, 0x00, 0x20, //0.-9. 0x1e, 0x2a, 0x0e, 0x0f, 0xbf, 0x23, 0x9b, 0x8b}; //FSEt-yno //LED字庫(kù)SPI初始化 void SpiInitDevice() { // 8 bits/char, input data sampled at end of data output time SpiOpenFlags oFlags = SPI_OPEN_MSTEN | SPI_OPEN_CKP_HIGH | SPI_OPEN_MODE8 | SPI_OPEN_ON; PORTSetPinsDigitalOut(IOPORT_B, BIT_9);//作為鎖存,1鎖存,0開(kāi)放 PPSOutput(2, RPB8, SDO2); // Set RB8 pin as output for SDO2 // Open SPI module, use SPI channel 2, use flags set above, Divide Fpb by 6 SpiChnOpen(2, oFlags, 6); } void SpiDoBurst(unsigned char *pBuff, unsigned char Len) { if (pBuff) { unsigned int i; PORTClearBits(IOPORT_B, BIT_9); for (i = 0; i < Len; i ) { SpiChnPutC(2, pBuff[ i]); } PORTSetBits(IOPORT_B, BIT_9); } } //LED初始化 void Led() { static unsigned char ledBuff[4] = {0x00, 0x00, 0x00, 0x00}; static int led = 0; int i,n; SpiDoBurst(ledBuff, 4); //LED顯示 4,1,2,3 switch(g_status) { case SHOW_PERIOD: led=g_period; ledBuff[3]=0b00010110;//Led_lib[1]; break; case SHOW_DUTY: led=g_duty; ledBuff[3]=0b01001110;//Led_lib[2]; break; case SHOW_SET_PERIOD: led=g_set_period; ledBuff[3]=0b00010100;//Led_lib[3]; break; case SHOW_SET_DUTY: led=g_set_duty; ledBuff[3]=0b01001100;//Led_lib[4]; break; case SET_PERIOD: led=g_set_period; ledBuff[3]=0b00010100;//Led_lib[3]; break; case SET_DUTY: led=g_set_duty; ledBuff[3]=0b01001100;//Led_lib[4]; break; } i=led/100; i=i; ledBuff[0]=Led_lib[ i]; led=led0; i=led/10; ledBuff[1]=Led_lib[ i]; i=led; ledBuff[2]=Led_lib[ i]; n ; if(n=2) flag=1; } void pwminit() { RPB13Rbits.RPB13R=0b0101;//外設(shè)端口映射為OC4 OC4CON=0; OC4R=0; OC4RS=0; OC4CON=0X06; //PWM無(wú)故障模式 OpenTimer2(T2_ON|T2_SOURCE_INT|T2_PS_1_1,g_period); //基定時(shí)器初始 OC4CONSET=0X8000; //使能OC4 // mT2SetIntPriority(1); // mT2IntEnable(1); } //void __ISR(_TIMER_2_VECTOR,ipl1) Timer2(void) //{ // // mT2ClearIntFlag(); // OC4RS=g_duty; //若由輸出比較的基定時(shí)器2刷新值,則會(huì)隨著PWM周期的太小刷新過(guò)快,會(huì)與定時(shí)器1的中斷多次沖突造成定時(shí)器1無(wú)法正常工作。 // PR2=g_period; //} void Timer1Init() { // Timer1@1ms OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_1, PERIOD); // Set up the timer interrupt with a priority of 2 INTEnable(INT_T1, INT_ENABLED); INTSetVectorPriority(INT_TIMER_1_VECTOR, INT_PRIORITY_LEVEL_5); INTSetVectorSubPriority(INT_TIMER_1_VECTOR, INT_SUB_PRIORITY_LEVEL_0); } //??1???? void __ISR(_TIMER_1_VECTOR, ipl5) Timer1Handler(void) { // Clear the interrupt flag INTClearFlag(INT_T1); OC4RS=g_duty; PR2=g_period;//由定時(shí)器1統(tǒng)一更新周期和占空比 g_led_cnt ; if(g_led_cnt > 100) //0.1s { g_led_cnt = 0; g_led_flag = 1; } g_btn_cnt ; if(g_btn_cnt > 5) //5ms { g_btn_cnt = 0; g_btn_flag = 1; } } //設(shè)為數(shù)字端口,當(dāng)有足夠電壓改變1與0的轉(zhuǎn)換才有信號(hào) void BtnInit() { ANSELAbits.ANSA0 = 0; ANSELAbits.ANSA1 = 0; // ANSELBbits.ANSB3 = 0; ANSELBbits.ANSB14 = 0; } //???? void Button(void) { static int btn0=0,btn1=0,btn2=0,btn3=0,n=0; if(PORTAbits.RA0 == 0) //sel { btn0 ; if(btn0 == BTN_DELAY) { switch(g_status) { case SHOW_PERIOD: g_status=SHOW_SET_PERIOD; break; case SHOW_DUTY: g_status=SHOW_SET_DUTY; break; case SHOW_SET_PERIOD: g_status=SHOW_PERIOD; break; case SHOW_SET_DUTY: g_status=SHOW_DUTY; break; } // if (g_status>=SHOW_SET_PERIOD) // { // g_status=SHOW_PERIOD; // OC4CONCLR=0X8000; // } // else // { // g_status=SHOW_SET_PERIOD; // g_set_period=g_period; // g_set_duty=g_duty; // // } } } else btn0 = 0; if(PORTAbits.RA1 == 0) // { btn1 ; if(btn1 == BTN_DELAY) { switch(g_status) { case SHOW_PERIOD: g_status=SHOW_DUTY; break; case SHOW_DUTY: g_status=SHOW_PERIOD; break; case SHOW_SET_PERIOD: if (g_set_period<999) g_set_period ; g_period=g_set_period; break; // g_status=SHOW_SET_DUTY; // break; case SHOW_SET_DUTY: if (g_set_duty<100) g_set_duty ; g_duty=g_set_duty; break; // g_status=SHOW_SET_PERIOD; // break; // case SET_PERIOD: // case SET_DUTY: } } } else btn1 = 0; if(PORTBbits.RB14 == 0) //- { btn2 ; if(btn2 == BTN_DELAY) { switch(g_status) { case SHOW_PERIOD: g_status=SHOW_DUTY; break; case SHOW_DUTY: g_status=SHOW_PERIOD; break; case SHOW_SET_PERIOD: if (g_set_period>0) g_set_period--; g_period=g_set_period; break; // g_status=SHOW_SET_DUTY; // break; case SHOW_SET_DUTY: if (g_set_duty>0) g_set_duty--; g_duty=g_set_duty; break; // g_status=SHOW_SET_PERIOD; // break; // case SET_PERIOD: // if (g_set_period>0) g_set_period--; // break; // case SET_DUTY: // if (g_set_duty>0) g_set_duty--; // break; } } } else btn2 = 0; // if(PORTBbits.RB3 == 0) //enter // { // btn3 ; // if(btn3 == BTN_DELAY) // { // switch(g_status) // { // case SHOW_PERIOD: // OC1CONCLR=0X8000; // break; // case SHOW_DUTY: // OC1CONCLR=0X8000; // break; // case SHOW_SET_PERIOD: // g_status=SET_PERIOD; // OC1CONCLR=0X8000; // break; // case SHOW_SET_DUTY: // g_status=SET_DUTY; // OC1CONCLR=0X8000; // break; // case SET_PERIOD: // g_period=g_set_period; // g_status=SHOW_PERIOD; // while(!flag); // flag=0; // pwminit(); // break; // case SET_DUTY: // g_duty=g_set_duty; // g_status=SHOW_PERIOD; // while(!flag); // flag=0; // pwminit(); // break; // } // } // } // else // btn3 = 0; } int main(int argc, char** argv) { int task=0; SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE); INTDisableInterrupts(); INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR); SpiInitDevice(); BtnInit(); Timer1Init(); pwminit(); INTEnableInterrupts(); while(1) { switch(task) { case 0: if(g_led_flag > 0) { g_led_flag = 0; Led(); } break; case 1: if(g_btn_flag > 0) { g_btn_flag = 0; Button(); } default: break; } task ; if(task > 1) task = 0; } return (EXIT_SUCCESS); } 附一: 表11-2: 輸出引腳選擇
0.png (51.5 KB, 下載次數(shù): 138)
下載附件
2015-12-19 20:21 上傳
例如:RPA0Rbits.RPA0R=0b0101;或 PPSOutput(1,RPA0,OC1); 第1組 即RPA0引腳作為OC1使用
例如:RPB15Rbits.RPB15R=0b0011; 或 PPSOutput(1,RPB15,SS1); 輸入引腳映射選擇 SDI1Rbits.SDI1R=0B0110; 或 PPSInput(2,SDI1,RPC8) 第2組 //數(shù)據(jù)輸入1口映射給RPC8 附二 初始化相關(guān)位定義 bit 15 ON:輸出比較外設(shè)使能位 1 = 使能輸出比較外設(shè)。 0 = 禁止輸出比較外設(shè),不會(huì)消耗電流。允許進(jìn)行SFR 修改。該寄存器中其他位的狀態(tài)不會(huì)受該位置1 或清零影響。 注: 使用1:1 PBCLK 分頻比時(shí),在清零模塊ON 位的指令之后,用戶的軟件不應(yīng)立即在SYSCLK 周期中讀/ 寫(xiě)外設(shè)的SFR。 bit 14 FRZ:調(diào)試異常模式凍結(jié)位 1 = 在CPU 進(jìn)入調(diào)試異常模式時(shí)停止工作 0 = 在CPU 進(jìn)入調(diào)試異常模式時(shí)繼續(xù)工作 注: FRZ 僅在調(diào)試異常模式下可寫(xiě),在正常模式下強(qiáng)制為0。 bit 13 SIDL:IDLE (空閑)模式停止位 1 = 在CPU 進(jìn)入IDLE (空閑)模式時(shí)停止工作 0 = 在IDLE (空閑)模式下繼續(xù)工作 bit 12-6 保留:寫(xiě)入0 ;忽略讀操作 bit 5 OC32:32 位比較模式位 1 = OCxR<31:0> 和/ 或OCxRS<31:0> 用于與32 位定時(shí)器源進(jìn)行比較 0 = OCxR<15:0> 和OCxRS<15:0> 用于與16 位定時(shí)器源進(jìn)行比較 bit 4 OCFLT:PWM 故障條件狀態(tài)位(1) 1 = 發(fā)生了PWM 故障條件(僅可用硬件清零) 0 = 未發(fā)生PWM 故障條件 注: 僅當(dāng)OCM<2:0> = 111 時(shí),才使用該位。 bit 3 OCTSEL:輸出比較定時(shí)器選擇位 1 = Timer3 作為該OCMP 模塊的時(shí)鐘源 0 = Timer2 作為該OCMP 模塊的時(shí)鐘源 關(guān)于輸出比較模塊可用的特定時(shí)基,請(qǐng)參見(jiàn)器件數(shù)據(jù)手冊(cè)。 bit 2-0 OCM<2:0>:輸出比較模式選擇位 111 = OCx 處于PWM 模式;故障引腳使能 110 = OCx 處于PWM 模式;故障引腳禁止 101 = 初始化OCx 引腳為低電平;在OCx 引腳上產(chǎn)生連續(xù)輸出脈沖 100 = 初始化OCx 引腳為低電平;在OCx 引腳上產(chǎn)生單輸出脈沖 011 = 比較事件使OCx 引腳電平翻轉(zhuǎn) 010 = 初始化OCx 引腳為高電平;比較事件強(qiáng)制OCx 引腳為低電平 001 = 初始化OCx 引腳為低電平;比較事件強(qiáng)制OCx 引腳為高電平 000 = 輸出比較外設(shè)被禁止,但會(huì)繼續(xù)消耗電流 轉(zhuǎn)載請(qǐng)說(shuō)明出處謝謝 |