[菜农助学交流] 菜农M0助学板PWM呼吸灯小练(寄存器操作方式)

[复制链接]
 楼主| tear086 发表于 2011-4-10 16:41 | 显示全部楼层 |阅读模式
本帖最后由 tear086 于 2011-4-19 21:05 编辑

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

main.h

  1. #ifndef __MAIN_H__
  2. #define __MAIN_H__
  3. #include <stdio.h>
  4. /*********************************************************
  5. * 系统寄存器映射及库头文件
  6. *********************************************************/
  7. #include "NUC1xx.h" // 系统寄存器映射
  8. #include "DrvSYS.h"
  9. #include "DrvGPIO.h"
  10. #include "DrvUART.h"
  11. /**********************************************************
  12. * 自定义宏
  13. **********************************************************/
  14. #define APP_DEBUG
  15. #ifdef APP_DEBUG
  16.     #define PRINT printf
  17. #else
  18.     #define PRINT
  19. #endif
  20. /**********************************************************
  21. * 函数申明
  22. **********************************************************/
  23. extern char GetChar(void);
  24. extern void PFN_UART_CALLBACK(void);
  25. /**********************************************************
  26. * 宏及变量申明
  27. **********************************************************/
  28. typedef enum{NO=0, YES=!NO}bool;
  29. volatile bool g_tmr0_5ms = NO;
  30. volatile bool g_breathing_led = NO; // 呼吸灯标志
  31. volatile uint8_t g_duty_cnt = 0;
  32. volatile bool g_duty_acc_dec = YES;
  33. #endif /* __MAIN_H__ */
mian.c

  1. #include "main.h"
  2. /**********************************************************
  3. * 系统上电初始化
  4. **********************************************************/
  5. void MAIN_INIT(void)
  6. {
  7.     UNLOCKREG();
  8.     {   /* 配置系统时钟 */
  9.         SYSCLK->WRCON.XTL12M_EN = 1; //  设定12M外部晶振
  10.         DrvSYS_Delay(5000); // 等待时钟就绪
  11.         DrvSYS_SelectPLLSource(E_SYS_EXTERNAL_12M); // 选择12MHz为PLL输入
  12.         DrvSYS_Open(50000000); // 打开50MHz
  13.     }      
  14.     {   /* 配置串口 */
  15.         STR_UART_T param;
  16.         
  17.         DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC, 0); //使能UART时钟
  18.         DrvGPIO_InitFunction(E_FUNC_UART0);    // 复用功能引脚设置
  19.                                                          
  20.         param.u32BaudRate        = 115200;    // 波特率
  21.         param.u8cDataBits        = DRVUART_DATABITS_8;  // 数据位
  22.         param.u8cStopBits        = DRVUART_STOPBITS_1;  // 停止位
  23.         param.u8cParity          = DRVUART_PARITY_NONE;    // 校验位
  24.         param.u8cRxTriggerLevel  = DRVUART_FIFO_1BYTES;    // FIFO存储深度1字节
  25.         param.u8TimeOut             = 0; // FIFO超时设定
  26.         DrvUART_Open(UART_PORT0, &param); // 串口开启、结构体整体赋值
  27.                
  28.         // 串口的中断类型比较丰富,此处仅打开接收中断
  29.         DrvUART_EnableInt(UART_PORT0, DRVUART_RDAINT, (PFN_DRVUART_CALLBACK*)PFN_UART_CALLBACK);
  30.         DrvUART_ClearIntFlag(UART_PORT0, DRVUART_RDAINT);
  31.     }
  32.     {   /* 配置GPIO */
  33.         NVIC_DisableIRQ(GPAB_IRQn);
  34.         NVIC_DisableIRQ(GPCDE_IRQn);
  35.         DrvGPIO_Open(E_GPB, 10, E_IO_OUTPUT); // 蜂鸣器
  36.         DrvGPIO_ClrBit(E_GPB, 10); // 关蜂鸣器
  37.     }
  38.     {   /* 配置TMR0 */
  39.         NVIC_DisableIRQ(TMR0_IRQn);
  40.         // 第一步 使能和选择定时器时钟源及使能定时器模块         
  41.         SYSCLK->CLKSEL1.TMR0_S = 0; // 选择12Mhz作为定时器时钟源
  42.         SYSCLK->APBCLK.TMR0_EN =1;  // 使能定时器0
  43.         TIMER0->TCSR.CEN = 1;       // 使能定时器模块
  44.         // 第二步 选择操作模式   
  45.         TIMER0->TCSR.MODE = 1; // 选择周期模式
  46.         TIMER0->TCSR.CRST = 1; // 清加1计数器   
  47.         // 第三步 输出时钟周期 = 定时器时钟源周期*(8位预分频因子 + 1) * (24位比较因子TCMP)
  48.         TIMER0->TCSR.PRESCALE = 11; // 12分频
  49.         TIMER0->TCMPR = 5000; // 12M/12/5000=200Hz, 5ms
  50.         // 第四步 使能中断
  51.         TIMER0->TISR.TIF = 1; // 清中断  
  52.         TIMER0->TCSR.IE = 1; // 使能中断
  53.         NVIC_EnableIRQ(TMR0_IRQn);  // 使能TMR0中断
  54.         // 第五步 使能定时器模块
  55.         TIMER0->TCSR.CRST = 1; // 复位向上计数器
  56.             TIMER0->TCSR.CEN = 1; // 使能TMR0
  57.         //TIMER0->TCSR.TDR_EN=1; // 无需读取加1计数器值
  58.     }
  59.     {   /* 配置PWM0 */
  60.         NVIC_DisableIRQ(PWMA_IRQn);
  61.         // 第一步,GPIO初始化
  62.         SYS->GPAMFP.PWM0_AD13=1;   
  63.         // 第二步,使能和选择PWM时钟源
  64.         SYSCLK->CLKSEL1.PWM01_S = 0; // 选择12MHz作为PWM时钟源
  65.         SYSCLK->APBCLK.PWM01_EN = 1; // 使能PWM时钟
  66.         // PWM clock = clock source/(Prescale + 1)*divider(分数形式)
  67.         PWMA->PR.CP01=119; // [0, 255] 预分频Prescale, 置零则停止输出时钟
  68.                             // 120分频
  69.         PWMA->CSR.CSR0=4; // 时钟次分频clock divider->0:/2, 1:/4, 2:/8, 3:/16, 4:/1
  70.                           // 所得时钟频率为12M/120/1=100kHz, 10us
  71.                           // 此处频率与CNR每一等份时间相对应
  72.         // 第三步,选择PWM操作模式   
  73.         PWMA->CR.CH0MOD=1; // 0: 单次触发模式, 1: 自动重载模式
  74.                             // 设置CH1MOD为从0到1后,CNR和CMR会被自动清零        
  75.         PWMA->CR.CH0INV=0; // 反向使能->0:失能, 1:使能
  76.         PWMA->CR.DZEN01=0; // 死区发生器使能->0:失能, 1:使能
  77.         /* 第四步,选择PWM频率计占空比 */
  78.         PWMA->CNR0=1; // 定时器载入值 [0,65535]
  79.                       // PWM周期=PWM clock/(CNR+1)
  80.                       //        =1*10us
  81.         PWMA->CMR0=PWMA->CNR0>>1; // PWM比较值,[0,65535]
  82.                                   // PWM占空比 =  (CMR+1)/(CNR+1)
  83.                                   // CMR >= CNR 输出高电平   
  84.         // 第五步,使能PWM输出
  85.         PWMA->CR.CH0EN=0; // 使能PWM核:0,失能;1使能;此处先失能,留作以后效果比对
  86.         PWMA->OE.PWM0=1; // 输出到引脚:0,失能;1,使能
  87.         // 第六步 中断设置
  88.         PWMA->IER.PWMIE0=0; // 使能中断:0,失能;1,使能
  89. //        NVIC_EnableIRQ(PWMA_IRQn);
  90.     }
  91.     LOCKREG();
  92. }
  93. /**********************************************************
  94. * TMR0 ISR
  95. **********************************************************/
  96. void TMR0_IRQHandler(void) __irq
  97. {   // 注意:ISR内必须清中断
  98.     TIMER0->TISR.TIF = 1; // 清中断  

  99.     g_tmr0_5ms = YES;   
  100. }
  101. /**********************************************************
  102. * UART0 回调函数
  103. **********************************************************/
  104. void PFN_UART_CALLBACK(void)
  105. {   // 注意:回调函数内无须清中断
  106.     switch(GetChar()) {
  107.         case '1':
  108.             g_breathing_led = NO; // 失能呼吸灯

  109.             PWMA->OE.PWM0=0; // 输出到引脚:0,失能;1,使能
  110.             PWMA->PR.CP01=40; // 40分频
  111.             PWMA->CSR.CSR0=3; // 12M/40/16 = 10kHz, 100us
  112.             PWMA->CNR0=9999; // PWM周期=10000*100us=1s
  113.             PWMA->CMR0=PWMA->CNR0>>1; // PWM占空比= (CMR+1)/(CNR+1)=50%
  114.             PWMA->CR.CH0EN=1; // 使能PWM核:0,失能;1使能
  115.             PWMA->OE.PWM0=1; // 输出到引脚:0,失能;1,使能
  116.                     
  117.             PRINT("亮灭灯:频率1Hz,占空比50%\r");
  118.             break;
  119.         case '2':
  120.             g_breathing_led = YES; // 使能呼吸灯

  121.             PWMA->OE.PWM0=0; // 输出到引脚:0,失能;1,使能
  122.             PWMA->PR.CP01=119; // 分频
  123.             PWMA->CSR.CSR0=1; // 12M/120/1 = 100kHz, 10us
  124.             PWMA->CR.CH0EN=1; // 使能PWM核:0,失能;1使能
  125.             PWMA->OE.PWM0=1; // 输出到引脚:0,失能;1,使能
  126.             g_duty_cnt = 0;

  127.             PRINT("呼吸灯:频率1.25Hz,占空比自己算\r");
  128.             break;
  129.         case 'q':
  130.             g_breathing_led = NO; // 失能呼吸灯

  131.             PWMA->CR.CH0EN=0; // 使能PWM核:0,失能;1使能
  132.             PWMA->OE.PWM0=0; // 输出到引脚:0,失能;1,使能

  133.             PRINT("关灯\r");
  134.             break;            
  135.         default: break;        
  136.     }                    
  137. }
  138. /**********************************************************
  139. * 主函数
  140. **********************************************************/
  141. int main(void)
  142. {
  143.     MAIN_INIT(); // 上电初始化系统     
  144.    
  145.     while(1) {
  146.         if(g_tmr0_5ms != NO) {
  147.             g_tmr0_5ms = NO;

  148.             if(g_breathing_led != NO) {
  149.                 if(g_duty_acc_dec != NO){
  150.                     g_duty_cnt ++;
  151.                     if(g_duty_cnt == 199) g_duty_acc_dec = NO;
  152.                 }
  153.                 else {
  154.                     g_duty_cnt --;
  155.                     if(g_duty_cnt == 0) g_duty_acc_dec = YES;
  156.                 }

  157.                 PWMA->CNR0=199; // PWM周期=200*10us=2ms
  158.                                 // 呼吸灯周期=2ms*200=0.4s,1.25Hz
  159.                 PWMA->CMR0=g_duty_cnt; // PWM占空比= (CMR+1)/(CNR+1)=?
  160.             }
  161.         }

  162.         if(0) break; // 跳出大循环
  163.     }
  164.    
  165.     DrvUART_Close(UART_PORT0);
  166.     return 0;
  167. }

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
hotpower 发表于 2011-4-10 17:12 | 显示全部楼层
哈哈,出气灯,不错,回家发裤子
Swallow_0322 发表于 2011-4-10 17:51 | 显示全部楼层
顶!:P
plc_avr 发表于 2011-4-11 11:22 | 显示全部楼层
建议将整个工程上传,呵呵。
 楼主| tear086 发表于 2011-4-12 19:16 | 显示全部楼层
4# plc_avr BSP包不在其内。文件目录如下:
--NUC100SeriesBSP
--PWM_LED
----docs
----list
----obj
----src

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
plc_avr 发表于 2011-4-13 08:40 | 显示全部楼层
谢谢,昨天编译未通过,今天再试一下。:)
crestxa 发表于 2011-4-17 15:40 | 显示全部楼层
运行可以,但是没看到现象
jack_shine 发表于 2012-2-14 12:48 | 显示全部楼层
代码这么多啊
jack_shine 发表于 2012-2-14 12:48 | 显示全部楼层
代码这么多啊
nxslhc 发表于 2012-3-31 22:58 | 显示全部楼层
看的挺有感啊
kzkzkzkzkz008 发表于 2012-11-6 13:52 | 显示全部楼层
请问楼主,笔记本没串口咋用啊?我新手,刚刚回离线下载程序。。。。求赐教
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:個人博客:yuphone.cnblogs.com 聯絡方式:張亞峰 15013013265@qq.com

0

主题

120

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:個人博客:yuphone.cnblogs.com 聯絡方式:張亞峰 15013013265@qq.com

0

主题

120

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部