zoukankan      html  css  js  c++  java
  • [原创].菜农M0助学板PWM呼吸灯小练(寄存器操作方式)

    已发帖至:http://bbs.21ic.com/viewthread.php?tid=229192

    关于菜农M0助学板(NUC120):http://bbs.21ic.com/iclist-78.html

    使用串口0的接收中断,来控制闪灯类型。上电缺省不开灯。
      发1,1Hz亮灭灯,占空比为50%;
      发2,1.25Hz呼吸灯,占空比自己算;
      发q,关灯

    main.h

    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    #include <stdio.h>
    
    /*********************************************************
    * 系统寄存器映射及库头文件
    *********************************************************/
    #include "NUC1xx.h" // 系统寄存器映射
    #include "DrvSYS.h"
    #include "DrvGPIO.h"
    #include "DrvUART.h"
    /**********************************************************
    * 自定义宏
    **********************************************************/
    #define APP_DEBUG
    
    #ifdef APP_DEBUG
        #define PRINT printf
    #else
        #define PRINT 
    #endif
    /**********************************************************
    * 函数申明
    **********************************************************/
    extern char GetChar(void);
    extern void PFN_UART_CALLBACK(void);
    /**********************************************************
    * 宏及变量申明
    **********************************************************/
    typedef enum{NO=0, YES=!NO}bool;
    volatile bool g_tmr0_5ms = NO;
    volatile bool g_breathing_led = NO; // 呼吸灯标志
    volatile uint8_t g_duty_cnt = 0;
    volatile bool g_duty_acc_dec = YES;
    
    #endif /* __MAIN_H__ */
    

    main.c

    #include "main.h"
    /**********************************************************
    * 系统上电初始化
    **********************************************************/
    void MAIN_INIT(void)
    {
        UNLOCKREG();
        {   /* 配置系统时钟 */
            SYSCLK->PWRCON.XTL12M_EN = 1; //  设定12M外部晶振
            DrvSYS_Delay(5000); // 等待时钟就绪
            DrvSYS_SelectPLLSource(E_SYS_EXTERNAL_12M); // 选择12MHz为PLL输入
            DrvSYS_Open(50000000); // 打开50MHz
        }      
        {   /* 配置串口 */
            STR_UART_T param;
            
            DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC, 0); //使能UART时钟
            DrvGPIO_InitFunction(E_FUNC_UART0);    // 复用功能引脚设置
                                                             
            param.u32BaudRate        = 115200;    // 波特率
            param.u8cDataBits        = DRVUART_DATABITS_8;  // 数据位
            param.u8cStopBits        = DRVUART_STOPBITS_1;  // 停止位
            param.u8cParity          = DRVUART_PARITY_NONE;    // 校验位
            param.u8cRxTriggerLevel  = DRVUART_FIFO_1BYTES;    // FIFO存储深度1字节
            param.u8TimeOut             = 0; // FIFO超时设定
            DrvUART_Open(UART_PORT0, &param); // 串口开启、结构体整体赋值
            
            // 串口的中断类型比较丰富,此处仅打开接收中断
            DrvUART_EnableInt(UART_PORT0, DRVUART_RDAINT, (PFN_DRVUART_CALLBACK*)PFN_UART_CALLBACK);
            DrvUART_ClearIntFlag(UART_PORT0, DRVUART_RDAINT);
        }
        {   /* 配置GPIO */
            NVIC_DisableIRQ(GPAB_IRQn);
            NVIC_DisableIRQ(GPCDE_IRQn);
            DrvGPIO_Open(E_GPB, 10, E_IO_OUTPUT); // 蜂鸣器 
            DrvGPIO_ClrBit(E_GPB, 10); // 关蜂鸣器
        }
        {   /* 配置TMR0 */
            NVIC_DisableIRQ(TMR0_IRQn);
            // 第一步 使能和选择定时器时钟源及使能定时器模块          
            SYSCLK->CLKSEL1.TMR0_S = 0; // 选择12Mhz作为定时器时钟源 
            SYSCLK->APBCLK.TMR0_EN =1;  // 使能定时器0
            TIMER0->TCSR.CEN = 1;       // 使能定时器模块
            // 第二步 选择操作模式    
            TIMER0->TCSR.MODE = 1; // 选择周期模式
            TIMER0->TCSR.CRST = 1; // 清加1计数器    
            // 第三步 输出时钟周期 = 定时器时钟源周期*(8位预分频因子 + 1) * (24位比较因子TCMP)
            TIMER0->TCSR.PRESCALE = 11; // 12分频
            TIMER0->TCMPR = 5000; // 12M/12/5000=200Hz, 5ms
            // 第四步 使能中断
            TIMER0->TISR.TIF = 1; // 清中断  
            TIMER0->TCSR.IE = 1; // 使能中断 
            NVIC_EnableIRQ(TMR0_IRQn);  // 使能TMR0中断
            // 第五步 使能定时器模块
            TIMER0->TCSR.CRST = 1; // 复位向上计数器
            TIMER0->TCSR.CEN = 1; // 使能TMR0
            //TIMER0->TCSR.TDR_EN=1; // 无需读取加1计数器值
        }
        {   /* 配置PWM0 */
            NVIC_DisableIRQ(PWMA_IRQn);
            // 第一步,GPIO初始化
            SYS->GPAMFP.PWM0_AD13=1;    
            // 第二步,使能和选择PWM时钟源
            SYSCLK->CLKSEL1.PWM01_S = 0; // 选择12MHz作为PWM时钟源
            SYSCLK->APBCLK.PWM01_EN = 1; // 使能PWM时钟
            // PWM clock = clock source/(Prescale + 1)*divider(分数形式)
            PWMA->PPR.CP01=119; // [0, 255] 预分频Prescale, 置零则停止输出时钟
                                // 120分频
            PWMA->CSR.CSR0=4; // 时钟次分频clock divider->0:/2, 1:/4, 2:/8, 3:/16, 4:/1
                              // 所得时钟频率为12M/120/1=100kHz, 10us
                              // 此处频率与CNR每一等份时间相对应
            // 第三步,选择PWM操作模式   
            PWMA->PCR.CH0MOD=1; // 0: 单次触发模式, 1: 自动重载模式
                                // 设置CH1MOD为从0到1后,CNR和CMR会被自动清零        
            PWMA->PCR.CH0INV=0; // 反向使能->0:失能, 1:使能
            PWMA->PCR.DZEN01=0; // 死区发生器使能->0:失能, 1:使能
            /* 第四步,选择PWM频率计占空比 */
            PWMA->CNR0=1; // 定时器载入值 [0,65535]
                          // PWM周期=PWM clock/(CNR+1)
                          //        =1*10us
            PWMA->CMR0=PWMA->CNR0>>1; // PWM比较值,[0,65535]
                                      // PWM占空比 =  (CMR+1)/(CNR+1)
                                      // CMR >= CNR 输出高电平    
            // 第五步,使能PWM输出
            PWMA->PCR.CH0EN=0; // 使能PWM核:0,失能;1使能;此处先失能,留作以后效果比对
            PWMA->POE.PWM0=1; // 输出到引脚:0,失能;1,使能
            // 第六步 中断设置
            PWMA->PIER.PWMIE0=0; // 使能中断:0,失能;1,使能
    //        NVIC_EnableIRQ(PWMA_IRQn); 
        }
        LOCKREG();
    }
    /**********************************************************
    * TMR0 ISR
    **********************************************************/
    void TMR0_IRQHandler(void) __irq
    {   // 注意:ISR内必须清中断
        TIMER0->TISR.TIF = 1; // 清中断  
    
        g_tmr0_5ms = YES;   
    }
    /**********************************************************
    * UART0 回调函数
    **********************************************************/
    void PFN_UART_CALLBACK(void)
    {   // 注意:回调函数内无须清中断
        switch(GetChar()) {
            case '1':
                g_breathing_led = NO; // 失能呼吸灯
    
                PWMA->POE.PWM0=0; // 输出到引脚:0,失能;1,使能
                PWMA->PPR.CP01=40; // 40分频
                PWMA->CSR.CSR0=3; // 12M/40/16 = 10kHz, 100us
                PWMA->CNR0=9999; // PWM周期=10000*100us=1s
                PWMA->CMR0=PWMA->CNR0>>1; // PWM占空比= (CMR+1)/(CNR+1)=50%
                PWMA->PCR.CH0EN=1; // 使能PWM核:0,失能;1使能
                PWMA->POE.PWM0=1; // 输出到引脚:0,失能;1,使能
                    
                PRINT("亮灭灯:频率1Hz,占空比50%\r");
                break;
            case '2':
                g_breathing_led = YES; // 使能呼吸灯
    
                PWMA->POE.PWM0=0; // 输出到引脚:0,失能;1,使能
                PWMA->PPR.CP01=119; // 分频
                PWMA->CSR.CSR0=1; // 12M/120/1 = 100kHz, 10us
                PWMA->PCR.CH0EN=1; // 使能PWM核:0,失能;1使能
                PWMA->POE.PWM0=1; // 输出到引脚:0,失能;1,使能
                g_duty_cnt = 0;
    
                PRINT("呼吸灯:频率1.25Hz,占空比自己算\r");
                break;
            case 'q':
                g_breathing_led = NO; // 失能呼吸灯
    
                PWMA->PCR.CH0EN=0; // 使能PWM核:0,失能;1使能
                PWMA->POE.PWM0=0; // 输出到引脚:0,失能;1,使能
    
                PRINT("关灯\r");
                break;            
            default: break;        
        }            
    }
    /**********************************************************
    * 主函数
    **********************************************************/
    int main(void)
    {
        MAIN_INIT(); // 上电初始化系统     
        
        while(1) {
            if(g_tmr0_5ms != NO) {
                g_tmr0_5ms = NO;
    
                if(g_breathing_led != NO) {
                    if(g_duty_acc_dec != NO){
                        g_duty_cnt ++;
                        if(g_duty_cnt == 199) g_duty_acc_dec = NO;
                    }
                    else {
                        g_duty_cnt --;
                        if(g_duty_cnt == 0) g_duty_acc_dec = YES;
                    }
    
                    PWMA->CNR0=199; // PWM周期=200*10us=2ms
                                    // 呼吸灯周期=2ms*200=0.4s,1.25Hz
                    PWMA->CMR0=g_duty_cnt; // PWM占空比= (CMR+1)/(CNR+1)=?
                } 
            }
    
            if(0) break; // 跳出大循环
        }
        
        DrvUART_Close(UART_PORT0);
        return 0;
    }

     2 1

    04112011005-new

  • 相关阅读:
    cf1100 F. Ivan and Burgers
    cf 1033 D. Divisors
    LeetCode 17. 电话号码的字母组合
    LeetCode 491. 递增的子序列
    LeetCode 459.重复的子字符串
    LeetCode 504. 七进制数
    LeetCode 3.无重复字符的最长子串
    LeetCode 16.06. 最小差
    LeetCode 77. 组合
    LeetCode 611. 有效三角形个数
  • 原文地址:https://www.cnblogs.com/yuphone/p/2011720.html
Copyright © 2011-2022 走看看