神农鼎 发表于 2023-10-7 19:34:01

PWM做DAC完整演示程序,用内部真12位ADC来保证精度@8H8K64U

PWM做DAC的完整演示程序,用内部真12位ADC来保证精度
用ADC的精度来, 保证PWM做DAC的精度, 完整演示程序
===详见 8H8K64U核心功能实验板,开天斧演示程序
===详见 32G12K128核心功能实验板,屠龙刀演示程序

========================================================
深圳国芯人工智能有限公司-工具软件 (stcai.com)

===详见 8H8K64U核心功能实验板,开天斧演示程序






===详见STC32G12K128核心功能实验板,屠龙刀演示程序











神农鼎 发表于 2023-10-7 19:51:51

/* --- Web: www.STCAI.com ---------------------------------------------*/

/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */

/*---------------------------------------------------------------------*/


/*************功能说明    **************

本例程基于STC8H8K64U核心实验板(开天斧)进行编写测试。

使用例程测试需要修改基准电压为VCC,将R114电阻移到R113。

从P1.0(PWM1P)输出16位的PWM, 输出的PWM经过RC滤波成直流电压送P1.4进行ADC采样并对输出结果进行反馈。

串口1配置为115200,8,n,1, 使用P3.0 P3.1接口通信, 下载后就可以直接测试。通过串口1设置占空比。

串口命令使用ASCII码的数字,比如: 10,就是设置占空比为10/256, 100: 就是设置占空比为100/256。

可以设置的值为0~256, 0为连续低电平, 256为连续高电平。

下载时, 选择时钟 22.1184MHz (用户可自行修改频率)。

******************************************/

#include "../comm/stc8h.h"   //包含此头文件后,不需要再包含"reg51.h"头文件
#include "stdio.h"
#include "intrins.h"

#define MAIN_Fosc       22118400L   //定义主时钟(精确计算115200波特率)

typedef unsigned char   u8;
typedef unsigned int    u16;
typedef unsigned long   u32;

/****************************** 用户定义宏 ***********************************/

#define Baudrate1       115200L
#define Timer0_Reload   (65536UL -(MAIN_Fosc / 1000))       //Timer 0 中断频率, 1000次/秒

#define PERIOD          255L   //PWM周期
#define THRESHOLD       2      //PWM调节差值门槛

#define UART1_BUF_LENGTH    128   //串口缓冲长度

/*****************************************************************************/


/*************本地变量声明    **************/

bit B_1ms;          //1ms标志
u8cnt200ms;

u8RX1_TimeOut;
u8TX1_Cnt;    //发送计数
u8RX1_Cnt;    //接收计数
bit B_TX1_Busy; //发送忙标志
u16 adc;
u16 duty;
u16 feedback;

u8 xdata RX1_Buffer;   //接收缓冲

void UART1_config(u8 brt);   // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
void UART1_TxByte(u8 dat);
void UpdatePwm(u16 pwm_value);
u16 Get_ADC12bitResult(u8 channel); //channel = 0~15

/******************** 主函数 **************************/
void main(void)
{
    u8i;
    u16 j;

    P_SW2 |= 0x80; //扩展寄存器(XFR)访问使能

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    P1M1 = 0x30;   P1M0 = 0x00;   //设置 P1.4,P1.5 为 ADC 口

    duty = 128;
    feedback = duty;

    //Timer0初始化
    AUXR = 0x80;    //Timer0 set as 1T, 16 bits timer auto-reload,
    TH0 = (u8)(Timer0_Reload / 256);
    TL0 = (u8)(Timer0_Reload % 256);
    ET0 = 1;    //Timer0 interrupt enable
    TR0 = 1;    //Tiner0 run

    //ADC初始化
    ADCTIM = 0x3f;      //设置 ADC 内部时序,ADC采样时间建议设最大值
    ADCCFG = 0x2f;      //设置 ADC 转换结果右对齐,时钟为系统时钟/2/16
    ADC_CONTR = 0x84;   //使能 ADC 模块

    PWMA_CCER1 = 0x00; //写 CCMRx 前必须先清零 CCxE 关闭通道
    PWMA_CCMR1 = 0x60; //设置 PWM1 模式1 输出
    PWMA_CCER1 = 0x05; //使能 CC1E 通道
    PWMA_CCMR1 |= 0x08; //输出比较预装载使能(CCxE为1才可写)

    PWMA_ARRH = (u8)(PERIOD>>8); //设置周期时间
    PWMA_ARRL = (u8)PERIOD;
    PWMA_CCR1H = (u8)(duty>>8);
    PWMA_CCR1L = (u8)duty;       //设置占空比时间

    PWMA_ENO = 0x01; //使能 PWM1P 输出
//PWMA_ENO = 0x02; //使能 PWM1N 输出
    PWMA_PS = 0x00;//高级 PWM1(P/N) 输出脚通道选择位, 0x00:P1.0/P1.1, 0x01:P2.0/P2.1, 0x02:P6.0/P6.1
    PWMA_BKR = 0x80; //使能主输出
    PWMA_CR1 |= 0x01; //开始计时

    UART1_config(2);    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
    EA = 1;   //打开总中断

    printf("PWM转DAC测试程序, 输入占空比为 0~256!\r\n");//UART1发送一个字符串

    while (1)
    {
      if(B_1ms)   //1ms到
      {
            B_1ms = 0;
            if(++cnt200ms >= 200)   //200ms读一次ADC
            {
                cnt200ms = 0;
                adc = Get_ADC12bitResult(4);//参数0~15,查询方式做一次ADC, 返回值就是结果
                j = (u16)((duty*4096UL)/(PERIOD+1));    //计算ADC采样理论值
                if(j>adc)
                {
                  if(((j-adc)>THRESHOLD) && (feedback<=PERIOD)) feedback++;
                }
                else
                {
                  if(((adc-j)>THRESHOLD) && (feedback>0)) feedback--;
                }
                printf("ADC=%u,duty=%u,feedback=%u\r\n",adc,duty,feedback);
                UpdatePwm(feedback);    //更新占空比
            }

            if(RX1_TimeOut > 0)   //超时计数
            {
                if(--RX1_TimeOut == 0)
                {
                  if((RX1_Cnt > 0) && (RX1_Cnt <= 3)) //限制为3位数字
                  {
                        F0 = 0; //错误标志
                        j = 0;
                        for(i=0; i<RX1_Cnt; i++)
                        {
                            if((RX1_Buffer >= '0') && (RX1_Buffer <= '9'))    //限定为数字
                            {
                              j = j * 10 + RX1_Buffer - '0';
                            }
                            else
                            {
                              F0 = 1; //接收到非数字字符, 错误
                              printf("错误! 接收到非数\xfd字字符! 占空比为0~%u!\r\n",(u16)PERIOD+1);
                              break;
                            }
                        }
                        if(!F0)
                        {
                            if(j > (PERIOD+1)) printf("错误! 输入占空比过\xfd大, 请不要大于%u!\r\n",(u16)PERIOD+1);
                            else
                            {
                              duty = j;
                              feedback = j;
                              UpdatePwm(duty);    //更新占空比
                              printf("更新占空比=%u.\r\n",duty);
                            }
                        }
                  }
                  elseprintf("错误! 输入字符过\xfd多! 例\xfd程限制3位数\xfd字!\r\n");//带FD编码汉字需在后面添加"\xfd"才能正常显示
                  RX1_Cnt = 0;
                }
            }
      }
    }
}

//========================================================================
// 函数: void UART1_TxByte(u8 dat)
// 描述: 发送一个字节.
// 参数: 无.
// 返回: 无.
// 版本: V1.0, 2014-6-30
//========================================================================
void UART1_TxByte(u8 dat)
{
    B_TX1_Busy = 1;
    SBUF = dat;
    while(B_TX1_Busy);
}

char putchar(char c)
{
        UART1_TxByte(c);
        return c;
}

//========================================================================
// 函数: void SetTimer2Baudraye(u16 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void SetTimer2Baudraye(u16 dat)// 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
    AUXR &= ~(1<<4);    //Timer stop
    AUXR &= ~(1<<3);    //Timer2 set As Timer
    AUXR |=(1<<2);    //Timer2 set as 1T mode
    T2H = dat / 256;
    T2L = dat % 256;
    IE2&= ~(1<<2);    //禁止中断
    AUXR |=(1<<4);    //Timer run enable
}

//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_config(u8 brt)    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
    /*********** 波特率使用定时器2 *****************/
    if(brt == 2)
    {
      AUXR |= 0x01;       //S1 BRT Use Timer2;
      SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / Baudrate1);
    }

    /*********** 波特率使用定时器1 *****************/
    else
    {
      TR1 = 0;
      AUXR &= ~0x01;      //S1 BRT Use Timer1;
      AUXR |=(1<<6);    //Timer1 set as 1T mode
      TMOD &= ~(1<<6);    //Timer1 set As Timer
      TMOD &= ~0x30;      //Timer1_16bitAutoReload;
      TH1 = (u8)((65536UL - (MAIN_Fosc / 4) / Baudrate1) / 256);
      TL1 = (u8)((65536UL - (MAIN_Fosc / 4) / Baudrate1) % 256);
      ET1 = 0;    //禁止中断
      INTCLKO &= ~0x02;//不输出时钟
      TR1= 1;
    }
    /*************************************************/

    SCON = (SCON & 0x3f) | 0x40;    //UART1模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
//PS= 1;    //高优先级中断
    ES= 1;    //允许中断
    REN = 1;    //允许接收
    P_SW1 &= 0x3f;
    P_SW1 |= 0x00;      //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
//PCON2 |=(1<<4);   //内部短路RXD与TXD, 做中继, ENABLE,DISABLE

    B_TX1_Busy = 0;
    TX1_Cnt = 0;
    RX1_Cnt = 0;
}

//========================================================================
// 函数: void UART1_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_int (void) interrupt 4
{
    if(RI)
    {
      RI = 0;
      RX1_Buffer = SBUF;
      if(++RX1_Cnt >= UART1_BUF_LENGTH)   RX1_Cnt = 0;    //防溢出
      RX1_TimeOut = 5;
    }

    if(TI)
    {
      TI = 0;
      B_TX1_Busy = 0;
    }
}

/********************** Timer0 1ms中断函数 ************************/
void timer0(void) interrupt 1
{
    B_1ms = 1;      //1ms标志
}

//========================================================================
// 函数: u16 Get_ADC12bitResult(u8 channel)
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC.
// 返回: 12位ADC结果.
// 版本: V1.0, 2012-10-22
//========================================================================
u16 Get_ADC12bitResult(u8 channel)//channel = 0~15
{
    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    while((ADC_CONTR & 0x20) == 0);   //wait for ADC finish
    ADC_CONTR &= ~0x20;   //清除ADC结束标志
    return(((u16)ADC_RES << 8) | ADC_RESL);
}

//========================================================================
// 函数: UpdatePwm(u16 pwm_value)
// 描述: 更新PWM值.
// 参数: pwm_value: pwm值, 这个值是输出高电平的时间.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void UpdatePwm(u16 pwm_value)
{
    PWMA_CCR1H = (u8)(pwm_value >> 8); //设置占空比时间
    PWMA_CCR1L = (u8)(pwm_value);
}


神农鼎 发表于 2023-10-7 19:53:36

/* --- Web: www.STCAI.com ---------------------------------------------*/

/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */

/*---------------------------------------------------------------------*/


/*************功能说明    **************

本例程基于STC32G核心转接板(屠龙刀)进行编写测试。

使用例程测试需要修改基准电压为VCC,将R114电阻移到R113。

从P1.0(PWM1P)输出16位的PWM, 输出的PWM经过RC滤波成直流电压送P1.4进行ADC采样并对输出结果进行反馈。

串口1配置为115200,8,n,1, 使用P3.0 P3.1接口通信, 下载后就可以直接测试。通过串口1设置占空比。

串口命令使用ASCII码的数字,比如: 10,就是设置占空比为10/256, 100: 就是设置占空比为100/256。

可以设置的值为0~256, 0为连续低电平, 256为连续高电平。

下载时, 选择时钟 22.1184MHz (用户可自行修改频率)。

******************************************/

#include "../comm/stc32g.h"   //包含此头文件后,不需要再包含"reg51.h"头文件
#include "stdio.h"
#include "intrins.h"

#define MAIN_Fosc       22118400L   //定义主时钟(精确计算115200波特率)

typedef unsigned char   u8;
typedef unsigned int    u16;
typedef unsigned long   u32;

/****************************** 用户定义宏 ***********************************/

#define Baudrate1       115200L
#define Timer0_Reload   (65536UL -(MAIN_Fosc / 1000))       //Timer 0 中断频率, 1000次/秒

#define PERIOD          255L   //PWM周期
#define THRESHOLD       2      //PWM调节差值门槛

#define UART1_BUF_LENGTH    128   //串口缓冲长度

/*****************************************************************************/


/*************本地变量声明    **************/

bit B_1ms;          //1ms标志
u8cnt200ms;

u8RX1_TimeOut;
u8TX1_Cnt;    //发送计数
u8RX1_Cnt;    //接收计数
bit B_TX1_Busy; //发送忙标志
u16 adc;
u16 duty;
u16 feedback;

u8RX1_Buffer;   //接收缓冲

void UART1_config(u8 brt);   // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
void UART1_TxByte(u8 dat);
void UpdatePwm(u16 pwm_value);
u16 Get_ADC12bitResult(u8 channel); //channel = 0~15

/******************** 主函数 **************************/
void main(void)
{
    u8i;
    u16 j;

    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    P1M1 = 0x30;   P1M0 = 0x00;   //设置 P1.4,P1.5 为 ADC 口

    duty = 128;
    feedback = duty;

    //Timer0初始化
    AUXR = 0x80;    //Timer0 set as 1T, 16 bits timer auto-reload,
    TH0 = (u8)(Timer0_Reload / 256);
    TL0 = (u8)(Timer0_Reload % 256);
    ET0 = 1;    //Timer0 interrupt enable
    TR0 = 1;    //Tiner0 run

    //ADC初始化
    ADCTIM = 0x3f;      //设置 ADC 内部时序,ADC采样时间建议设最大值
    ADCCFG = 0x2f;      //设置 ADC 转换结果右对齐,时钟为系统时钟/2/16
    ADC_CONTR = 0x84;   //使能 ADC 模块

    PWMA_CCER1 = 0x00; //写 CCMRx 前必须先清零 CCxE 关闭通道
    PWMA_CCMR1 = 0x60; //设置 PWM1 模式1 输出
    PWMA_CCER1 = 0x05; //使能 CC1E 通道
    PWMA_CCMR1 |= 0x08; //输出比较预装载使能(CCxE为1才可写)

    PWMA_ARRH = (u8)(PERIOD>>8); //设置周期时间
    PWMA_ARRL = (u8)PERIOD;
    PWMA_CCR1H = (u8)(duty>>8);
    PWMA_CCR1L = (u8)duty;       //设置占空比时间

    PWMA_ENO = 0x01; //使能 PWM1P 输出
//PWMA_ENO = 0x02; //使能 PWM1N 输出
    PWMA_PS = 0x00;//高级 PWM1(P/N) 输出脚通道选择位, 0x00:P1.0/P1.1, 0x01:P2.0/P2.1, 0x02:P6.0/P6.1
    PWMA_BKR = 0x80; //使能主输出
    PWMA_CR1 |= 0x01; //开始计时

    UART1_config(2);    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
    EA = 1;   //打开总中断

    printf("PWM转DAC测试程序, 输入占空比为 0~256!\r\n");//UART1发送一个字符串

    while (1)
    {
      if(B_1ms)   //1ms到
      {
            B_1ms = 0;
            if(++cnt200ms >= 200)   //200ms读一次ADC
            {
                cnt200ms = 0;
                adc = Get_ADC12bitResult(4);//参数0~15,查询方式做一次ADC, 返回值就是结果
                j = (u16)((duty*4096UL)/(PERIOD+1));    //计算ADC采样理论值
                if(j>adc)
                {
                  if(((j-adc)>THRESHOLD) && (feedback<=PERIOD)) feedback++;
                }
                else
                {
                  if(((adc-j)>THRESHOLD) && (feedback>0)) feedback--;
                }
                printf("ADC=%u,duty=%u,feedback=%u\r\n",adc,duty,feedback);
                UpdatePwm(feedback);    //更新占空比
            }

            if(RX1_TimeOut > 0)   //超时计数
            {
                if(--RX1_TimeOut == 0)
                {
                  if((RX1_Cnt > 0) && (RX1_Cnt <= 3)) //限制为3位数字
                  {
                        F0 = 0; //错误标志
                        j = 0;
                        for(i=0; i<RX1_Cnt; i++)
                        {
                            if((RX1_Buffer >= '0') && (RX1_Buffer <= '9'))    //限定为数字
                            {
                              j = j * 10 + RX1_Buffer - '0';
                            }
                            else
                            {
                              F0 = 1; //接收到非数字字符, 错误
                              printf("错误! 接收到非数\xfd字字符! 占空比为0~%u!\r\n",(u16)PERIOD+1);
                              break;
                            }
                        }
                        if(!F0)
                        {
                            if(j > (PERIOD+1)) printf("错误! 输入占空比过\xfd大, 请不要大于%u!\r\n",(u16)PERIOD+1);
                            else
                            {
                              duty = j;
                              feedback = j;
                              UpdatePwm(duty);    //更新占空比
                              printf("更新占空比=%u.\r\n",duty);
                            }
                        }
                  }
                  elseprintf("错误! 输入字符过\xfd多! 例\xfd程限制3位数\xfd字!\r\n");//带FD编码汉字需在后面添加"\xfd"才能正常显示
                  RX1_Cnt = 0;
                }
            }
      }
    }
}

//========================================================================
// 函数: void UART1_TxByte(u8 dat)
// 描述: 发送一个字节.
// 参数: 无.
// 返回: 无.
// 版本: V1.0, 2014-6-30
//========================================================================
void UART1_TxByte(u8 dat)
{
    B_TX1_Busy = 1;
    SBUF = dat;
    while(B_TX1_Busy);
}

char putchar(char c)
{
        UART1_TxByte(c);
        return c;
}

//========================================================================
// 函数: void SetTimer2Baudraye(u32 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void SetTimer2Baudraye(u32 dat)// 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
    T2R = 0;    //Timer stop
    T2_CT = 0;//Timer2 set As Timer
    T2x12 = 1;//Timer2 set as 1T mode
    T2H = (u8)(dat / 256);
    T2L = (u8)(dat % 256);
    ET2 = 0;    //禁止中断
    T2R = 1;    //Timer run enable
}

//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_config(u8 brt)    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
    /*********** 波特率使用定时器2 *****************/
    if(brt == 2)
    {
      S1BRT = 1;        //S1 BRT Use Timer2;
      SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / Baudrate1);
    }

    /*********** 波特率使用定时器1 *****************/
    else
    {
      TR1 = 0;
      S1BRT = 0;      //S1 BRT Use Timer1;
      T1_CT = 0;      //Timer1 set As Timer
      T1x12 = 1;      //Timer1 set as 1T mode
      TMOD &= ~0x30;//Timer1_16bitAutoReload;
      TH1 = (u8)((65536UL - (MAIN_Fosc / 4) / Baudrate1) / 256);
      TL1 = (u8)((65536UL - (MAIN_Fosc / 4) / Baudrate1) % 256);
      ET1 = 0;    //禁止中断
      TR1= 1;
    }
    /*************************************************/

    SCON = (SCON & 0x3f) | 0x40;    //UART1模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
//PS= 1;    //高优先级中断
    ES= 1;    //允许中断
    REN = 1;    //允许接收
    P_SW1 &= 0x3f;
    P_SW1 |= 0x00;      //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
//PCON2 |=(1<<4);   //内部短路RXD与TXD, 做中继, ENABLE,DISABLE

    B_TX1_Busy = 0;
    TX1_Cnt = 0;
    RX1_Cnt = 0;
}

//========================================================================
// 函数: void UART1_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_int (void) interrupt 4
{
    if(RI)
    {
      RI = 0;
      RX1_Buffer = SBUF;
      if(++RX1_Cnt >= UART1_BUF_LENGTH)   RX1_Cnt = 0;    //防溢出
      RX1_TimeOut = 5;
    }

    if(TI)
    {
      TI = 0;
      B_TX1_Busy = 0;
    }
}

/********************** Timer0 1ms中断函数 ************************/
void timer0(void) interrupt 1
{
    B_1ms = 1;      //1ms标志
}

//========================================================================
// 函数: u16 Get_ADC12bitResult(u8 channel)
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC.
// 返回: 12位ADC结果.
// 版本: V1.0, 2012-10-22
//========================================================================
u16 Get_ADC12bitResult(u8 channel)//channel = 0~15
{
    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    while(ADC_FLAG == 0);   //wait for ADC finish
    ADC_FLAG = 0;   //清除ADC结束标志
    return(((u16)ADC_RES << 8) | ADC_RESL);
}

//========================================================================
// 函数: UpdatePwm(u16 pwm_value)
// 描述: 更新PWM值.
// 参数: pwm_value: pwm值, 这个值是输出高电平的时间.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void UpdatePwm(u16 pwm_value)
{
    PWMA_CCR1H = (u8)(pwm_value >> 8); //设置占空比时间
    PWMA_CCR1L = (u8)(pwm_value);
}


神农鼎 发表于 2023-10-18 09:11:39




STC使用普通I/O口和电阻分压实现高速DAC例程-可做高速波形发生器 - ADC/比较器,DMA支持的12位ADC,轨到轨比较器,DAC - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)


神农鼎 发表于 2023-10-18 09:18:40

STC8单片机 + 【自制 R-2R电阻分压实现 DAC】播放WAV音频
用串口助手直接给STC8发送WAV文件,Xdata作为缓冲区,
STC8直接读取送到GPIO,经过8bit R-2R DAC播放,接个功放就能出声,这里是输入电脑录音。
卡顿是串口波特率和wav的采样率不匹配造成的:波特率230400bps,wav:pcm+22050Hz,单声道。

https://www.bilibili.com/video/BV1ut4y1W7X1

神农鼎 发表于 2023-10-18 09:22:19

USB / CAN 专题免费教学会议通知:
【USB 原理及实战,16课时】
===【10月/9号,10月/11号,10月/16号】教学视频已上传
===【10月/16号的 USB-HID 实战】教学视频超级精彩,已上传
===【10月/18号的 USB-CDC 实战】视频教学会议即将开始
线上视频授课:周一下午/周三下午,14:00 ~ 17:00;
腾讯会议号:885-5858-2739; (安装腾讯会议软件后,输入会议号即可)
参会学习立即【免费+包邮送】USB核心功能实验板
请帮忙转发给可能需要:从0开始了解USB和CAN的 同学/同事/老师/研发人员

【CAN 原理及实战,12课时】10月/23号, 10月/25号; 10月/30号;
线上视频授课:周一下午/周三下午,14:00 ~ 17:00;
腾讯会议号:885-5858-2739; (安装腾讯会议软件后,输入会议号即可)
参会学习立即【免费+包邮送】USB核心功能实验板
参会学习立即【免费+包邮送】CAN核心功能实验板,模拟的CAN收发器您自己补上
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=4526&extra=&page=1
请帮忙转发给可能需要:从0开始了解USB和CAN的 同学/同事/老师/研发人员


LLCF 发表于 2024-1-16 09:42:36

赞👍

神农鼎 发表于 2024-2-20 14:13:50


咫尺天涯 发表于 2024-2-20 16:55:00

学习了

小白 发表于 2024-3-3 09:39:46

DAC的精度有12位吗?
PWM的频率是多少?
页: [1] 2
查看完整版本: PWM做DAC完整演示程序,用内部真12位ADC来保证精度@8H8K64U