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

  • 相关阅读:
    JavaScript高级程序设计之元素大小
    软件测试面试必备的一些基础理论概念
    golang跨平台编译
    gin shoudBind
    requests
    excelize
    gin获取全部参数
    golang随机数及pipe
    不安全代码只会在使用 /unsafe 编译的情况下出现
    MongoDB 比较运算符 $eq$gt
  • 原文地址:https://www.cnblogs.com/yuphone/p/2011720.html
Copyright © 2011-2022 走看看