⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 零耗时低频宽脉冲软pwm信号控制keil c51演示程序(hotpower).txt

📁 零耗时低频宽脉冲软PWM信号控制Keil C51演示程序C51文件PwmDemo.c。在uV3中对PWM信号进行"实时仿真"效果逼真。
💻 TXT
📖 第 1 页 / 共 2 页
字号:
  ------------------------------------*/ 
  void sioproc() interrupt SIO_VECTOR using 2
  if (RI) {//接收中断
  RI = 0;
  /*-------------------------------------------- 
  在此加入用户串口接收代码
  ----------------------------------------------*/ 
  if (TI) {//发送中断
  TI = 0;
  /*-------------------------------------------- 
  在此加入用户串口发送代码
  ----------------------------------------------*/ 
  /*----------------------------------------------------------------------------- 
  定时器T2中断服务程序(20mS)
  零耗时低频宽脉冲软PWM信号控制演示程序 
  软件工作环境及要求: 
  MCU主频12MHz,软PWM控制IO模拟。PWM脉宽调节10uS 
  PWM频率20mS=50Hz, PWM高电平脉宽700uS~2300uS,PWM低电平脉宽19300uS~17700uS 
  "零耗时"并非不耗时。只是没用软件空等待等恼人的函数。 
  其主要原理是利用低频宽脉冲软PWM信号的“低速”而T2的16位定时器自动装载功能。 
  T2在每个PWM周期内中断两次。即PWM高电平和PWM低电平各中断1次。 
  合理应用RCAP2的预装载功能并进行简单的减法运算而轻松完成任务的要求。 
  本演示程序只需经过简单的修改,即可实现变PWM频率等功能。 
  为演示方便未用宏定义,否则会更通用。但必须在“低频宽脉冲”的相对条件下。 
  本文纯属虚构,若有雷同请原谅! 
  ------------------------------------------------------------------------------*/ 
  void t2proc() interrupt TF2_VECTOR using 1 
  static unsigned int PwmCount = 700;//系统内部PWM高电平PwmCount(用户无法访问) 
  /*----------------------------------------------------------------------------- 
  PWM软件IO模拟,任务中未加关PWM控制,可以再加限定/PWM电平信号翻转标志。 
  即:SystemBuffers.PwmCount=0为关闭PWM电平信号输出(PWM=0) 
  注意SystemBuffers.PwmCount不能过小. 
  本软PWM控制模块与Windows的原则相同 
  --不主张用户直接开展PWM管脚,而是控制SystemBuffers.PwmCount变量。 
  ------------------------------------------------------------------------------- 
  if (SystemBuffers.PwmCount == 0) {//关断PWM信号。(不主张用户直接开展PWM管脚) 
  PWM = 0;//关闭PWM电平信号输出,并强迫执行RCAP2 = 0 - PwmCount;RCAP2=0(最宽) 
  PwmCount = 0;//PWM高电平脉宽为0,PWM低电平脉宽为T2的最大定时时间。 
  ------------------------------------------------------------------------------*/ 
  PWM = ~PWM;//PWM电平信号翻转 
  TF2 = 0;//清除标志 
  if (PWM) {//在PWM高电平时至少有700uS的预算时间 
  /*--------------------------------------------------------------------- 
  用户只能改写全局变量SystemBuffers.PwmCount,不能改写静态变量PwmCount 
  ----------------------------------------------------------------------*/ 
  PwmCount = SystemBuffers.PwmCount;//应该在PWM下降沿处取用户PWM高电平PwmCount
  /*------------------------------------------------------------------------------ 
  此时RCAP2早已将PWM高电平PwmCount装入到TIMEER2中 
  故此时应该计算PWM低电平20mS-PwmCount到RCAP2中 
  ------------------------------------------------------------------------------*/ 
  //
  RCAP2 = 0 - (20000 - PwmCount);//注意定时器是+1器 
  RCAP2 = PwmCount - 20000;//(优化计算)注意定时器是+1器(RCAP2首次为-19300) 
  else {//在PWM低电平时至少有17700uS的预算时间 
  /*------------------------------------------------------------------------------ 
  此时RCAP2早已将PWM低电平20mS-PwmCount装入到TIMEER2中 
  故此时应该计算PWM高电平PwmCount到RCAP2中 
  ------------------------------------------------------------------------------- 
  RCAP2 = 0 - PwmCount;//注意定时器是+1器(RCAP2首次为-700) 
  /*------------------------------------------------------------------------------ 
  PWM高电平RCAP2定时时间 + PWM低电平RCAP2定时时间 = PWM周期20mS 
  ------------------------------------------------------------------------------- 
  void ClrWdt(void)//喂狗 
  WDTRST = 0x1e;//89s52内狗 
  WDTRST = 0xe1;//89s52内狗 
  void main(void) 
  MainInit();//系统初始化 
  while (1) {//主循环 
  IE
  |= 0xbf;//保证全部中断可靠 
  TCON |= 0x55;//保证定时器打开,外部中断为边沿触发. 
  PCON |= GF0_ | IDL_;//喂疯狗(GF0_=1)并进入空闲状态(IDL_=1) 
  _nop_(); 
  _nop_(); 
  C51的一些误区和注意事项(ZT)( 
  1)C忌讳绝对定位。 常看见初学者要求使用_at_,这是一种谬误,把C当作ASM看待了。在C中变量的定位是编译器的事情,初学者只要定义变量和变量的作 用域,编译器就把一个固定地址给这个变量。怎么取得这个变量的地址?要用指针。比如unsigned char data x;后,x的地址就是&x, 你只要查看这个参数,就可以在程序中知道具体的地址了。所以俺一看见要使用绝对定位的人,第一印象就是:这大概是个初学者。 
  2)设置SP的问题。 原因和1差不对,编译器在把所有变量和缓冲区赋予地址后,自动把最后一个字节开始的地方,作为SP的开始位置,所以初学者是不必 要去理会的。这体现C的优越性,很多事情C编译时候做了。
  3)用C的主程序结构: #include void main(void) { while(1); } 这是个最小的成功的C程序,包括头部文件和程序主体。头部文件的名词解释:引用的外部资源文件,这个文件包括了硬件信息和外部模块提供的可使用的函数和变量的说明。可以用文本方式打开reg52.h,仔细研究下,会有一些写程序的体会。
  4)这样构成一个C项目 在C中,常用项目来管理。项目一般分为两大块:C文件块和头部文件块。 我们常把不同功能写在不同的C文件中,依靠项目的管理,最后把所有文件连接起来,这样就可以得到可以烧录的HEX文件或BIN文件。 这些C文件中,有且只有唯一一个包括main()函数,和3)中一样的C文件。 用头部文件把各个不同的C互相连接起来。一个C文件基本上要对应有一个H头部文件,这个H文件就包含本C文件中可以提供给外面使 用的变量和函数,没有在H文件中列出的文件,可以算是该C文件的内部函数和变量,外部C不能使用。 例子:a.C: unsigned char i; unsigned char mWork; void Test1(void) { mWork++; } void Test2(void) { i++; }  a.h文件中: extern unsigned char i; extern void Test1(void); 这样主程序M.c中:#include /*C编译器内部自带的H文件,使用<>*/ #include "a.h" /*自定义的H文件,一般用""*/ void main(void) { Test1(); /*使用a.c模块文件中的函数*/ while(1){i++; /*使用a.c模块文件中的变量*/ } }
  5)51家族 核心都是基于8031的,有很多在此核心上进行扩展,有的把程序存储器放在内部:89c(S)51..,有的增加了RAM:89c(S)52..,有的增加 了一些专用硬件80C552...,有的改变时钟时序W77E58...。市面上现在常用的主要有ATMEL公司的AT89X系列,PHILIPS的P87(89)x,台 湾WINBOND的w77(78)x系列,Cygnal的C8051Fx系列。
  6)51单片机结构的C描述 这里不讲51的具体结构,只是引导初学者快速理解51单片机的物理结构。寄存器和IO及其它硬件设备的地址名称,在相应的C头部文件 中可以找到。51为reg51.h,52为reg52.h,以次类推,比如winbond的78E58就为w78e58.h这些H文件中的描述: srf,定义一个8位的设备。 srf16,定义一个16位的设备。 sbit,定义一个位的设备。 用这些语句定义后,就可以在C中象汇编一样使用这些硬件设备,这是单片机应用比标准C特殊的地方,其它差别很少。 
  7)在51系列中data,idata,xdata,pdata的区别 data:固定指前面0x00-0x7f的128个RAM,可以用acc直接读写的,速度最快,生成的代码也最小。 idata:固定指前面0x00-0xff的256个RAM,其中前128和data的128完全相同,只是因为访问的方式不同。idata是用类似C中的指针方式 访问的。汇编中的语句为:mox ACC,@Rx.(不重要的补充:c中idata做指针式的访问效果很好).xdata:外部扩展RAM,一般指外部0x0000-0xffff空间,用DPTR访问。 pdata:外部扩展RAM的低256个字节,地址出现在A0-A7的上时读写,用movx ACC,@Rx读写。这个比较特殊,而且C51好象有对此BUG, 建议少用。但也有他的优点,具体用法属于中级问题,这里不提。
   8)startup.a51的作用 和汇编一样,在C中定义的那些变量和数组的初始化就在startup.a51中进行,如果你在定义全局变量时带有数值,如unsigned char data xxx=100;,那startup.a51中就会有相关的赋值。如果没有=100,startup.a51就会把他清0。(startup.a51==变量的初始化)。 这些初始化完毕后,还会设置SP指针。对非变量区域,如堆栈区,将不会有赋值或清零动作。 有人喜欢改startup.a51,为了满足自己一些想当然的爱好,这是不必要的,有可能错误的。比如掉电保护的时候想保存一些变量, 但改startup.a51来实现是很笨的方法,实际只要利用非变量区域的特性,定义一个指针变量指向堆栈低部:0xff处就可实现。, 为什么还要去改? 可以这么说:任何时候都可以不需要改startup.a51,如果你明白它的特性。 
  新编万年历星期速算法C语言的实现(hotpower) 
  #include 
  code unsigned char WeekTab[] = {//闰年月星期表 
  (3 << 5) + 31,//1月 
  (6 << 5) + 29,//2月 
  (0 << 5) + 31,//3月 
  (3 << 5) + 30,//4月 
  (5 << 5) + 31,//5月 
  (1 << 5) + 30,//6月 
  (3 << 5) + 31,//7月 
  (6 << 5) + 31,//8月 
  (1 << 5) + 30,//9月 
  (4 << 5) + 31,//10月 
  (0 << 5) + 30,//11月 
  (2 << 5) + 31 //12月 
  /*------------------------------------------------------------------------------ 
  ---------- 
  2000年~2099年星期算法 
  -------------------------------------------------------------------------------- 
  ---------*/ 
  unsigned char WeekDay20(unsigned char y, unsigned char m, unsigned char d) 
  unsigned char week, day; 
  day = WeekTab[m - 1];//月表 
  week = day >> 5;//月星期数 
  day &= 0x1f;//月天数 
  if ((m < 3) && (y & 0x03)){//平年 
  if (m == 2) day--;//平年月天数 
  week++;//平年月表+1 
  y = y + (y >> 2);//年+年/4 
  week = (week +
  y + d + 2) % 7;//(星期=年+年/4+月表+2日)%7 
  return (week << 5) | day;//返回星期和月天数 
  /*------------------------------------------------------------------------------ 
  ---------- 
  0000年~9999年星期算法 
  -------------------------------------------------------------------------------- 
  ---------*/ 
  unsigned char WeekDay(unsigned char c, unsigned char y, unsigned char m,
  unsigned char d) 
  unsigned char week, day; 
  c &= 0x03;//百年%4 
  c = c | (c << 2);//百年%4*5 
  day = WeekTab[m - 1];//月表 
  week = day >> 5;//月星期数 
  day &= 0x1f;//月天数 
  if ((m < 3) && !((c == 0) | (y & ((y & 0x03) == 0)))){//平年 
  if (m == 2) day--;//平年月天数 
  week++;//平年月表+1 
  y = y + (y >> 2);//年+年/4 
  week = (week + c + y + d + 2) % 7;//(星期=百年%4*5+年+年/4+月表+日+2)%7 
  return (week << 5) | day;//返回星期和月天数 
  unsigned char BcdToBin(unsigned char val) 
  val = (val >> 4) * 10 + (val & 0x0f);//将BCD码转换为10进制数 
  return val;//返回10进制数 
  void main(void) 
  unsigned char c, y, m, d; 
  unsigned char cx, yx, mx, dx;
  unsigned char WDay, Week, Day; 
  /*--------------------------------------------------------- 
  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -