【STC单片机】通过ADC外部输入调节PWM占空比输出并串口打印当前脉冲值


  • 相关篇《【STC15系列】P1.3做ADC-使用内部基准计算外部电压并串口打印》
  • 《【STC单片机】3路PWM波形输出并串口打印当前脉冲值》

本示例演示基于STC15W408AS单片机,采用自制开发板,使用的是外部晶振16MHz。

  • 《【开源分享】自制STC15W408AS开发板》

这篇文章涉及了综合知识的运用。写这一篇文章的初衷是昨天睡觉前的想法,做一个外部可控可调的PWM输出的功能。今天将其程序整理出来并且验证了这一点。

注意:ADC输入引脚不能浮空,不然PWM输出将会是跳动的脉动输出。占空比将是一个随机的状态形式输出。

  • 功能实现内容:占空比可调,但是频率是固定的2.6666KHz的。如需调整频率,需要修改想要的宏定义的参数。

f=MAIN_Fosc /PWM_DUTY

/**PWM.h文件**/
#define     PWM_DUTY        6000        //定义PWM的周期,数值为PCA所选择的时钟脉冲个数。
#define     PWM_HIGH_MIN    80          //限制PWM输出的最小占空比, 避免中断里重装参数时间不够。
#define     PWM_HIGH_MAX    (PWM_DUTY - PWM_HIGH_MIN)       //限制PWM输出的最大占空比。
  • 设置 2KHz的频率
//频率f=MAIN_Fosc /PWM_DUTY
#define     PWM_DUTY        8000        //定义PWM的周期,数值为PCA所选择的时钟脉冲个数。
#define     PWM_HIGH_MIN    80          //限制PWM输出的最小占空比, 避免中断里重装参数时间不够。
#define     PWM_HIGH_MAX    (PWM_DUTY - PWM_HIGH_MIN)       //限制PWM输出的最大占空比。

  • 调节定位器时,串口监视器数据动态输出
  • 代码完善后,调试完成的输出,串口只是为了方便调试和观察,程序测试OK后,可以去掉串口功能的部分。

采用的是10K定位器接到到P1.3引脚上,作为外部模拟量输入

  • 接线图
  • ADC的基准电压源采用P1.1口
P1ASF = 0;
Get_ADC10bitResult(1);  //改变P1ASF后先读一次并丢弃结果, 让内部的采样电容的电压等于输入值.
Bandgap = Get_ADC10bitResult(1);   //读P1.1的电压为基准ADC, P1ASF=0, 0通道的电压值
  • PWM输出通道

采用的是PCA0,也可以切换到PCA1,或者PCA2,

  • 选择任意其中一组即可。
     if(pwm0 >= PWM_HIGH_MAX)    pwm0 = PWM_HIGH_MIN;PWMn_Update(PCA0,pwm0);if(pwm1 >= PWM_HIGH_MAX)    pwm1 = PWM_HIGH_MIN;PWMn_Update(PCA1,pwm1);if(pwm2 >= PWM_HIGH_MAX)    pwm2 = PWM_HIGH_MIN;PWMn_Update(PCA2,pwm2);
  • PWM输出引脚
PCA0----P25
PCA1----P26
PCA2----P27
  • 示波器采集的数据波形

  • 最大占空比时的波形
  • 最小占空比

ADC模拟量数据转换

该函数数据类型必须满足被处理的数据,在这个函数实现上掉坑里了,刚开始认为定义一个无符号整型类型来存放就够了,转换出来的值完全不是预期值。

  • 该函数实现了,将ADC采集的模拟量的值范围0~1023,转换为80 ~ 5920对应值。
/********************** 模拟量映射函数 ************************/
long map( long x,  long in_min,  long in_max,  long out_min,  long out_max)
{return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
  • 说明一点的是:STC15W408AS只有2个定时器,全部用完了。定时器0用于ADC采集,定时器2用于串口波特率发生器。STC15W408AS是没有定时器1的。
  • ADC采集有2个方案

方式一是直接采用读值,另一种是采集16次去平均值。通过宏定义选择其一即可。

 #define Cal_MODE    0    //每次测量只读1次ADC. 分辨率0.01V#define Cal_MODE    1   //每次测量连续读16次ADC 再平均计算. 分辨率0.01V

主程序代码


/*************  功能说明    **************双串口全双工中断方式收发通讯程序。
注意:
通过PC向MCU发送数据, MCU收到后通过串口把收到的数据原样返回.******************************************/
#include    "config.h"
#include "stdio.h"
#include "USART.h"
#include "PWM.h"
#include "ADC.h"#define   Cal_MODE    0    //每次测量只读1次ADC. 分辨率0.01V
//  #define Cal_MODE    1   //每次测量连续读16次ADC 再平均计算. 分辨率0.01V
//typedef   unsigned char   u8;
//typedef   unsigned int    u16;
//typedef   unsigned long   u32;volatile bit    B_4ms;          //1ms标志volatile u16 msecond;        //计时
u16 Bandgap;    //void  delay_ms(unsigned int ms)
{unsigned int i;do{i = MAIN_Fosc / 13000;while(--i)    ;   //14T per loop}while(--ms);
}
/********************** 模拟量映射函数 ************************/
long map( long x,  long in_min,  long in_max,  long out_min,  long out_max)
{return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}//========================================================================
// 函数: void main(void)
// 描述: 主函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void main(void)
{u8 i;int   Duty ;int   j;PCA_Init();   //PCA初始化
//  P0M1 = 0;  P0M0 = 0;  //设置为准双向口
//  P1M1 = 0;  P1M0 = 0;  //设置为准双向口P1M1 = 0x00; P1M0 = 0x00; P1M1 |= (1<<3);     // 把ADC口设置为高阻输入P1M0 &= ~(1<<3);P1ASF = (1<<3);        //P1.3做ADCADC_CONTR = 0xE0;    //90T, ADC power on
//  P2M1 = 0;  P2M0 = 0;  //设置为准双向口P2M1 &= ~(0xe0);  //P2.7 P2.6 P2.5 设置为推挽输出P2M0 |=  (0xe0);P3M1 = 0; P3M0 = 0;  //设置为准双向口
//  P4M1 = 0;  P4M0 = 0;  //设置为准双向口
//  P5M1 = 0;  P5M0 = 0;  //设置为准双向口
//  P6M1 = 0;  P6M0 = 0;  //设置为准双向口
//  P7M1 = 0;  P7M0 = 0;  //设置为准双向口// S1_USE_P30P31();Timer0Init();//定时器0初始化InitSerialPort();         //初始化串口,波特率9600,8bit数据位,1停止位,无校验EA = 1;   //允许总中断//   PrintString1("STC15F2K60S2 UART1 Test Prgramme!\r\n");    //SUART1发送一个字符串while (1){// delay_ms(500);  P10 = !P10;if(pwm0 >= PWM_HIGH_MAX)  pwm0 = PWM_HIGH_MAX;//       if(pwm1 >= PWM_HIGH_MAX)    pwm1 = PWM_HIGH_MAX;
//      PWMn_Update(PCA1,pwm1);//       if(pwm2 >= PWM_HIGH_MAX)    pwm2 = PWM_HIGH_MAX;
//      PWMn_Update(PCA2,pwm2);if(B_4ms)    //5ms到达标志位{B_4ms = 0;if(++msecond >= 250)    //计数到达1S{msecond = 0;#if (Cal_MODE == 0)//=================== 只读1次ADC, 10bit ADC. 分辨率0.01V ===============================P1ASF = 0;Get_ADC10bitResult(1);    //改变P1ASF后先读一次并丢弃结果, 让内部的采样电容的电压等于输入值.Bandgap = Get_ADC10bitResult(1); //读P1.1的电压为基准ADC, P1ASF=0, 0通道的电压值P1ASF = 1<<3;j = Get_ADC10bitResult(3);  //读外部电压ADC//    j = (u16)((u32)j * 507 / Bandgap); //计算外部电压, Bandgap为5.07V, 测电压分辨率0.01Vprintf("\t ADC =%d \t\n",j); pwm0 = (u16)map(j, 0, 1023,80, 5920);//将映射的值赋值给pwm0printf("\t pwm0 =%u \t\n",pwm0 );#endif//==========================================================================//===== 连续读16次ADC 再平均计算. 分辨率0.01V =========#if (Cal_MODE == 1)P1ASF = 0;Get_ADC10bitResult(1); //改变P1ASF后先读一次并丢弃结果, 让内部的采样电容的电压等于输入值.for(j=0, i=0; i<16; i++){j += Get_ADC10bitResult(1); //读P11内部基准ADC, P1ASF=0, 读1通道}Bandgap = j >> 4;  //16次平均P1ASF = (1<<3);       //P1.3做ADCfor(j=0, i=0; i<16; i++){j += Get_ADC10bitResult(3); //读外部电压ADC}j = j >> 4;   //16次平均pwm0= (u16)map(j, 0, 1023, 80, 5920);//将映射的值赋值给pwm0//pwm0 = j;printf("\t pwm0 =%d \t\n",j); //j = (u16)((u32)j * 507 / Bandgap);   //计算外部电压, Bandgap为5.07V, 测电压分辨率0.01V#endif      //==========================================================================//Duty=map(pwm0, 80, 5920, 0, 100);//将pwm0转换为占空比串口输出PWMn_Update(PCA0,pwm0);//PCA0--P25,PCA2--P26//   printf("占空比:%u \r\n",Duty);}}//   printf("pwm0:%u \t pwm1:%u \t pwm2:%u\r\n",pwm0,pwm1,pwm2);   //SUART1发送一个字符串}
}/********************** Timer0 1ms中断函数 ************************/
void timer0 (void) interrupt 1
{B_4ms = 1;        //1ms标志
}
  • 程序架构

程序源码

链接:https://pan.baidu.com/s/1pTDkLEafN-MFihnq4l1fNQ
提取码:xonl

【STC单片机】通过ADC外部输入调节PWM占空比输出并串口打印当前脉冲值相关推荐

  1. ESP32 通过Web图形控件调节PWM占空比输出

    ESP32 通过Web图形控件调节PWM占空比输出

  2. STC单片机通过ADC分段采样读按键实现方法

    STC单片机通过ADC分段采样读按键实现方法 ✨在阅读官方FreeRTOS for STC32G12K128开源工程当中有使用到ADC键盘计算键码功能块,底层实现原理也很简单,就是通过串联电阻分压的方 ...

  3. 【单片机】P3口输入,P1口输出

    [单片机]P3口输入,P1口输出 代码详解(方法一) 代码详解(方法二) 代码详解(方法一) #include <reg51.h> #include <intrins.h> / ...

  4. 串口 单片机 文件_STM32物联网实战项目 HAL裸机开发09 串口打印

    就喜欢你关注我- HAL裸机开发09 - 串口打印 综合信息1.获取开发工具    微信公众号后台发送消息  -  工具2.获取开发板       淘宝搜索店铺  -  硬件家园3.快速了解平台    ...

  5. 单片机ADC采用输入电压范围的调节

    本文以STM32F429IGT6单片机为例. STM32F429IGT6有 3 个 ADC,每个 ADC有 12 位.10 位.8 位和 6 位可选,每个ADC有 16 个外部通道.另外还有两个内部 ...

  6. stc15系列c语言pwm编程,STC单片机C语言程序设计 第25章 STC单片机增强型PWM原理及实现.docx...

    STC单片机C语言程序设计 第25章 STC单片机增强型PWM原理及实现 STC单片机增强型PWM发生器原理及应用主 讲:何宾Email:hebin@mail.buct.edu.cn2016.03增强 ...

  7. YX133具有12位ADC与16位PWM的8位OTP单片机,SOP和QFN小封装单片机适合电子烟等便携产品使用

    1.1 产品描述 YX133 是一款以OTP程序为基础的8位微处理器,集成高精准度的8(6+2)通道12位的ADC(VREFHmin=1V),6个8位PWM(或3个16位PWM)生成器,1个硬件比较器 ...

  8. STC单片机硬件PWM的使用分析

    STC单片机(具有PCA功能的),怎么实现可变频率的PWM输出?很多朋友还在使用定时器做可变频PWM, 这里我就介绍怎么使用硬件PWM,在定时器0的分频基数下设计PWM. 首先看CMOD这个寄存器,这 ...

  9. STC单片机LCD1602四线驱动模式显示ADC采样电压和温度

    STC单片机LCD1602四线驱动模式显示ADC采样电压和温度

  10. 基于STC单片机的两轮平衡车设计

    给大家传福利了..后续继续共享基于Arduino/安卓Android/树莓派raspberry等平台的两轮车设计 这是我前年暑假做的一个小项目,今年拿出来整理了下当毕设了(当然毕设里添加了许多其他元素 ...

最新文章

  1. Objective-C语法简记
  2. 练习 MongoDB 操作 —— 备份篇(三)
  3. 简述电子计算机的用途和特点_计算机基础试题及答案
  4. div.php织梦自定义表判断不能为空,织梦自定义表单字段为必填项的教程
  5. 给Clouderamanager集群里安装基于Hive的大数据实时分析查询引擎工具Impala步骤(图文详解)...
  6. python—迭代器
  7. python多线程gil_Python 多线程、多进程 (一)之 源码执行流程、GIL
  8. linux修改磁盘盘符,debian下修改磁盘阵列盘符
  9. 四针手表指的是什么_1000~1500元的男士手表推荐
  10. Type TIMESTAMP(3) of table field ‘onSellTime‘ does not match with the physical type TIMESTAMP(6)
  11. 逾期了,如何消除不良记录?
  12. 去杠杆高歌猛进,借呗会倒闭吗?
  13. 软件工程第四周作业 - 四则运算
  14. Angular2 指令
  15. 基于苹果自研芯片的 Mac 电脑对安全意味着什么?
  16. H.264 无参考视频质量评价方法 (使用了基于遗传编程方法的符号回归)
  17. ubuntu jdk install
  18. python入侵个人电脑的步骤图解台式_入侵渗透专用的python小脚本脚本安全 -电脑资料...
  19. bzoj3668: [Noi2014]起床困难综合症
  20. java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet

热门文章

  1. 【单位换算】存储单位(bit Byte KB MB GB TB PB EB ZB YB BB)时间单位(ms μs ns ps)长度单位(dm cm mm μm nm pm fm am zm ym)
  2. 效率工具+WPS复选框显示太阳问题解决方法
  3. 什么是顶级域名,二级域名和三级域名
  4. 怎么配置计算机的ip,怎么设置电脑IP地址
  5. 基于似然比检验统计量的异常轨迹检测
  6. 计算机字节与位的换算,计算机字节换算(计算机字节换算器)
  7. LibVLC —— 《基于Qt的LibVLC专业开发技术》视频教程
  8. 寻址方式(立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址)
  9. Ubuntu 14.04 引导修复(Boot Repair)(双系统修复一)
  10. 20191124_射雕侠侣和天龙八部小说分类