找回密码
 立即注册
查看: 196|回复: 1

ADC+PWM+串口的演示程序,给一个,STC8H8K64U@【AI助手】

[复制链接]
已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25432
发表于 2026-7-8 14:52:01 | 显示全部楼层 |阅读模式
STC8H8K64U, ADC+PWM+串口的演示程序,给一个

截图202607081451306840.jpg
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25432
 楼主| 发表于 2026-7-8 14:52:37 | 显示全部楼层

好的,我已经查阅了STC8H8K64U的ADC、PWM和串口相关手册内容。现在我来编写一个完整的演示程序。


STC8H8K64U ADC+PWM+串口 综合演示程序

以下是一个完整的单文件C语言演示程序,功能说明如下:

功能概述:

  • 使用 ADC通道0(P1.0) 采集模拟电压(如电位器分压)
  • 使用 PWMA通道1(PWM1P,默认P1.0,本例切换至P6.0) 输出PWM,占空比跟随ADC值变化
  • 使用 串口1(P3.0 RxD, P3.1 TxD) 以115200bps定时上报ADC值和当前PWM占空比
  • 主频使用内部IRC 24MHz
/*
 * STC8H8K64U ADC + PWM + 串口 综合演示程序
 *
 * 功能说明:
 *   1. ADC通道0 (P1.0) 采集外部模拟电压
 *   2. PWMA通道1 (PWM1P) 输出PWM,占空比随ADC值变化
 *      - PWM1P引脚选择:P6.0(通过PWMA_PS设置)
 *      - PWM频率 = 24MHz / (PSCR+1) / (ARR+1) = 24MHz / 1 / 1000 = 24KHz
 *   3. 串口1 (P3.0 RxD, P3.1 TxD) 115200bps, 8n1
 *      - 定时通过串口发送ADC值和PWM占空比
 *   4. 主频:内部IRC 24MHz
 *
 * 硬件连接:
 *   - P1.0 (ADC0) 接电位器中心抽头(分压输入)
 *   - P6.0 (PWM1P) 接示波器或LED(通过限流电阻)
 *   - P3.0 (RxD) / P3.1 (TxD) 接USB转串口模块
 *
 * 下载时选择时钟 24MHz (内部IRC)
 */

#include "stc8h.h"
#include "intrins.h"

#define MAIN_Fosc    24000000UL    // 主时钟频率 24MHz

// 串口波特率重装值(定时器2作为波特率发生器,1T模式)
// 波特率 = SYSclk / 4 / (65536 - T2H_T2L)
#define UART_BRT     (65536UL - (MAIN_Fosc / 4) / 115200)

// PWM参数
#define PWM_PERIOD   999           // 自动重装载值 (ARR),PWM周期 = 24MHz/1/(999+1) = 24KHz
#define PWM_PSC      0             // 预分频值 (PSCR),PWM时钟不分频

// 全局变量
unsigned int g_adc_value;          // ADC转换结果(12位右对齐)
unsigned int g_pwm_duty;           // PWM占空比比较值
bit g_uart_busy;                   // 串口发送忙标志
bit g_1ms_flag;                    // 1ms定时标志
unsigned int g_tick_count;         // 毫秒计数器

// 函数声明
void System_Init(void);
void ADC_Init(void);
unsigned int ADC_Read(unsigned char channel);
void PWM_Init(void);
void PWM_SetDuty(unsigned int duty);
void UART1_Init(void);
void UART1_SendByte(unsigned char dat);
void UART1_SendString(unsigned char *str);
void UART1_SendNumber(unsigned int num);
void Timer0_Init(void);
void delay_ms(unsigned int ms);

/***************************** 主函数 *****************************/
void main(void)
{
    unsigned int adc_val;
    unsigned int duty_val;

    System_Init();          // I/O口初始化
    ADC_Init();             // ADC初始化
    PWM_Init();             // PWM初始化
    UART1_Init();           // 串口1初始化
    Timer0_Init();          // 定时器0初始化(1ms基准)

    EA = 1;                 // 开启总中断

    UART1_SendString("STC8H8K64U ADC+PWM+UART Demo Start!\r\n");

    while (1)
    {
        if (g_1ms_flag)
        {
            g_1ms_flag = 0;
            g_tick_count++;

            // 每500ms采集一次ADC并更新PWM,同时通过串口输出
            if (g_tick_count >= 500)
            {
                g_tick_count = 0;

                // 读取ADC通道0(P1.0),12位右对齐
                adc_val = ADC_Read(0);
                g_adc_value = adc_val;

                // 将12位ADC值映射到PWM占空比(0 ~ PWM_PERIOD)
                // ADC范围0~4095,映射到0~PWM_PERIOD
                duty_val = (unsigned long)adc_val * PWM_PERIOD / 4095;
                g_pwm_duty = duty_val;
                PWM_SetDuty(duty_val);

                // 通过串口发送数据
                UART1_SendString("ADC:");
                UART1_SendNumber(adc_val);
                UART1_SendString("  PWM:");
                UART1_SendNumber(duty_val);
                UART1_SendString("\r\n");
            }
        }
    }
}

/********************* 系统初始化(I/O口) *********************/
void System_Init(void)
{
    P_SW2 |= 0x80;          // 使能访问XFR(扩展寄存器)

    // 所有I/O口设置为准双向口
    P0M0 = 0x00; P0M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    P4M0 = 0x00; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
    P6M0 = 0x00; P6M1 = 0x00;
    P7M0 = 0x00; P7M1 = 0x00;

    // P1.0设置为高阻输入(ADC通道)
    P1M0 &= ~0x01;
    P1M1 |= 0x01;
}

/********************* ADC初始化 *********************/
void ADC_Init(void)
{
    ADCTIM = 0x3F;          // 设置ADC内部时序:CSSETUP=0, CSHOLD=01, SMPDUTY=11111
    ADCCFG = 0x2F;          // RESFMT=1(右对齐),SPEED=1111(最慢时钟,SYSclk/2/16)
    ADC_CONTR = 0x80;       // 打开ADC电源
    delay_ms(2);            // 等待ADC电源稳定(约1ms)
}

/********************* ADC读取函数(查询方式) *********************/
unsigned int ADC_Read(unsigned char channel)
{
    unsigned int res;

    ADC_CONTR = 0x80 | 0x40 | (channel & 0x0F);  // 启动ADC转换,选择通道
    _nop_();
    _nop_();

    while (!(ADC_CONTR & 0x20));    // 等待ADC_FLAG置位
    ADC_CONTR &= ~0x20;             // 清除ADC_FLAG

    // 12位右对齐:ADC_RES[3:0]为高4位,ADC_RESL[7:0]为低8位
    res = ((unsigned int)ADC_RES << 8) | ADC_RESL;
    return res;
}

/********************* PWM初始化(PWMA通道1) *********************/
void PWM_Init(void)
{
    // PWMA通道1输出脚选择:P6.0 (PWM1P)
    PWMA_PS = 0x02;         // C1PS[1:0]=10,选择P6.0/P6.1

    // 配置通道1为PWM模式1输出
    PWMA_CCER1 = 0x00;      // 写CCMRx前必须先关闭CCxE
    PWMA_CCMR1 = 0x60;      // OC1M[2:0]=110(PWM模式1),OC1PE=1(预装载使能)
    PWMA_CCER1 = 0x01;      // CC1E=1(使能输出),CC1P=0(高电平有效)

    // 设置PWM周期和预分频
    PWMA_PSCRH = (unsigned char)(PWM_PSC >> 8);
    PWMA_PSCRL = (unsigned char)(PWM_PSC);
    PWMA_ARRH  = (unsigned char)(PWM_PERIOD >> 8);
    PWMA_ARRL  = (unsigned char)(PWM_PERIOD);

    // 初始占空比50%
    PWMA_CCR1H = (unsigned char)((PWM_PERIOD / 2) >> 8);
    PWMA_CCR1L = (unsigned char)(PWM_PERIOD / 2);

    // 使能PWM1P输出
    PWMA_ENO = 0x01;        // ENO1P=1

    // 使能主输出并启动计数器
    PWMA_BKR = 0x80;        // MOE=1(主输出使能)
    PWMA_CR1 = 0x01;        // CEN=1(开始计时)
}

/********************* 设置PWM占空比 *********************/
void PWM_SetDuty(unsigned int duty)
{
    if (duty > PWM_PERIOD)
        duty = PWM_PERIOD;

    PWMA_CCR1H = (unsigned char)(duty >> 8);
    PWMA_CCR1L = (unsigned char)(duty);
}

/********************* 串口1初始化(115200bps, 8n1) *********************/
void UART1_Init(void)
{
    unsigned int brt;

    brt = (unsigned int)UART_BRT;

    // 配置串口1模式1(8位UART,可变波特率)
    SCON = 0x50;            // SM0=0, SM1=1(模式1), REN=1(允许接收)

    // 使用定时器2作为波特率发生器
    AUXR |= 0x01;           // S1ST2=1,选择定时器2作为串口1波特率发生器
    AUXR |= 0x04;           // T2x12=1,定时器2使用1T模式
    T2H = (unsigned char)(brt >> 8);
    T2L = (unsigned char)(brt);
    AUXR |= 0x10;           // T2R=1,启动定时器2

    g_uart_busy = 0;
    ES = 1;                 // 使能串口1中断
}

/********************* 串口1发送一个字节(中断方式) *********************/
void UART1_SendByte(unsigned char dat)
{
    while (g_uart_busy);    // 等待上次发送完成
    g_uart_busy = 1;
    SBUF = dat;
}

/********************* 串口1发送字符串 *********************/
void UART1_SendString(unsigned char *str)
{
    while (*str)
    {
        UART1_SendByte(*str++);
    }
}

/********************* 串口1发送数字(十进制) *********************/
void UART1_SendNumber(unsigned int num)
{
    unsigned char buf[6];
    unsigned char i;
    unsigned char len;

    if (num == 0)
    {
        UART1_SendByte('0');
        return;
    }

    len = 0;
    while (num > 0)
    {
        buf[len++] = (unsigned char)(num % 10) + '0';
        num /= 10;
    }

    for (i = len; i > 0; i--)
    {
        UART1_SendByte(buf[i - 1]);
    }
}

/********************* 定时器0初始化(1ms中断) *********************/
void Timer0_Init(void)
{
    // 定时器0:1T模式,16位自动重装载
    // 1ms = 24000000 / 1000 = 24000 个时钟周期
    // 重装值 = 65536 - 24000 = 41536 = 0xA240
    AUXR |= 0x80;           // T0x12=1,定时器0使用1T模式
    TMOD &= 0xF0;           // 定时器0模式0(16位自动重装载)
    TH0 = 0xA2;
    TL0 = 0x40;
    ET0 = 1;                // 使能定时器0中断
    TR0 = 1;                // 启动定时器0
}

/********************* 毫秒延时(查询方式) *********************/
void delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
    {
        // 24MHz下约1ms
        for (j = 0; j < 6000; j++)
        {
            _nop_();
        }
    }
}

/********************* 串口1中断服务函数 *********************/
void UART1_ISR(void) interrupt 4
{
    if (TI)
    {
        TI = 0;
        g_uart_busy = 0;
    }
    if (RI)
    {
        RI = 0;             // 清除接收标志(本例未使用接收)
    }
}

/********************* 定时器0中断服务函数 *********************/
void Timer0_ISR(void) interrupt 1
{
    g_1ms_flag = 1;
}

程序说明

模块 配置详情
系统时钟 内部IRC 24MHz
ADC 通道0(P1.0),12位分辨率,右对齐,查询方式读取
PWM PWMA通道1(PWM1P),引脚选择P6.0,频率 24KHz,占空比0~100%
串口1 P3.0(RxD)/P3.1(TxD),115200bps,8n1,中断方式发送
定时器0 1ms中断基准,用于定时触发ADC采集和串口输出(每500ms一次)

使用步骤

  1. 硬件连接:

    • P1.0 接电位器中心抽头(两端分别接VCC和GND)
    • P6.0 接示波器或LED(串330Ω电阻到GND)
    • P3.0/P3.1 接USB转串口模块(CH340G/CP2102等)
  2. 下载设置:

    • 打开 AiCube-ISP(STC-ISP) 下载软件
    • 选择型号 STC8H8K64U
    • 设置 IRC频率为24MHz
    • 加载本程序生成的HEX文件,下载到芯片
  3. 观察结果:

    • 串口助手(115200,8n1)每500ms收到类似数据:ADC:2048 PWM:499
    • 旋转电位器,ADC值和PWM占空比同步变化
    • 用示波器观察P6.0,可见PWM波形占空比随电位器调节而变化

注意:如果使用P1.0作为ADC输入,而PWM默认也在P1.0输出,本程序已通过 PWMA_PS 将PWM1P切换到P6.0,避免引脚冲突。


🔍 搜索 "STC8H8K64U ADC+PWM+串口的演示程序 给一个"

📌 相关论坛讨论

  1. PWM做DAC完整演示程序,用内部真12位ADC来保证精度@8H8K64U
  2. 老刘爱捣鼓示波器,开源程序,OLED12864, ADC, PWM
  3. 54-DMA-ADC采样数据自动存储,STC8H8K64U实验箱演示程序, STC8H2K32U, STC8H2K12U, ST

⏱️ 查找用时 12.4s | 总回答用时 44.5s

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-8 01:13 , Processed in 0.068855 second(s), 47 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表