打印
[通用8051核FLASH系列]

HC89F0541的PWM3输出经滤波后用ADC检测并用OLED显示

[复制链接]
1614|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 芯圣电子官方QQ 于 2023-7-20 10:12 编辑

前几天在芯圣电子官网买了几块 HC89F0541 开发板,第一次接触芯圣MCU,看中的是它的端口全映射功能,比如,PWM、UART、IIC 等输入输出可以映射到任意IO口输入输出。

//本例子使用PWM3输出占空比可变方波,R+C+R+C 阻容滤波
//然后使用ADC检测经滤波后的电平,在IIC接口的OLE显示屏上显示





微信图片_20210228134604.jpg (359.47 KB )

微信图片_20210228134604.jpg

HC8051 ADC PWM3 IIC SH1106 OLED.rar

49.28 KB

使用特权

评论回复
沙发
panxiaoyi|  楼主 | 2021-2-28 13:52 | 只看该作者
//
//本例子使用PWM3输出占空比可变方波,R+C+R+C电容滤波
//然后使用ADC检测经滤波后的电平,在IIC接口的OLE显示屏上显示
//
#define        ALLOCATE_EXTERN
#include "HC89F0541.h"
#include "0805FONT.h"
#include "DELAY.h"
#include "MCUIIC.h"
#include "SH1106.h"
#include "MCUADC.h"
#include "MCUPWM.h"


unsigned int n, adc_dat16;
unsigned char i, adc_dat8;


int main(void)
{       
        CLKSWR = 0x51;                                                            //选择内部高频RC为系统时钟,内部高频RC 2分频,Fosc=16MHz
        CLKDIV = 0x01;                                                            //Fosc 1分频得到Fcpu,Fcpu=16MHz
       
        ADC_init();
        IIC_init();
        OLED_init();
        PWM3_init();
       
        OLED_Clear();
        OLED_gotoxy(15,1);
        OLED_string("HC8051 ==> SH1106");
        OLED_gotoxy(12,5);
        OLED_string("21IC.COM PANXIAOYI");


        while(1)
        {               
    WDTC |= 0x10;                       //看门狗默认开启,程序必须定时清零看门狗


                OLED_gotoxy(52,3);
                OLED_show(i);


                PWM3_ratio(i);
               
                for(n=2500; n; n--)                 //数值太大的话要记得清零看门狗
                {
                        WDTC |= 0x10;
                  OLED_gotoxy(32,7);
                       
                        adc_dat8=ADC_read8(5);
                  OLED_show(adc_dat8);
                       
                        OLED_code(' ');
                       
                        adc_dat16=ADC_read16(6);
                  OLED_show(adc_dat16);
                }
                if(i<100) i++; else i=0;
        }          
}

使用特权

评论回复
板凳
panxiaoyi|  楼主 | 2021-2-28 13:53 | 只看该作者


#ifndef __0805FONT_H__
#define __0805FONT_H__           


//5*8字符字模
code unsigned char FONT__0805[]={      
0x00, 0x00, 0x00, 0x00, 0x00,   // sp  
0x00, 0x00, 0x2f, 0x00, 0x00,   // !  
0x00, 0x07, 0x00, 0x07, 0x00,   // "  
0x14, 0x7f, 0x14, 0x7f, 0x14,   // #  
0x24, 0x2a, 0x7f, 0x2a, 0x12,   // $  
0x62, 0x64, 0x08, 0x13, 0x23,   // %  
0x36, 0x49, 0x55, 0x22, 0x50,   // &  
0x00, 0x05, 0x03, 0x00, 0x00,   // ’  
0x00, 0x1c, 0x22, 0x41, 0x00,   // (  
0x00, 0x41, 0x22, 0x1c, 0x00,   // )  
0x14, 0x08, 0x3E, 0x08, 0x14,   // *  
0x08, 0x08, 0x3E, 0x08, 0x08,   // +  
0x00, 0x00, 0xA0, 0x60, 0x00,   // ,  
0x08, 0x08, 0x08, 0x08, 0x08,   // -  
0x00, 0x60, 0x60, 0x00, 0x00,   // .  
0x20, 0x10, 0x08, 0x04, 0x02,   // /  
0x3E, 0x51, 0x49, 0x45, 0x3E,   // 0  
0x00, 0x42, 0x7F, 0x40, 0x00,   // 1  
0x42, 0x61, 0x51, 0x49, 0x46,   // 2  
0x21, 0x41, 0x45, 0x4B, 0x31,   // 3  
0x18, 0x14, 0x12, 0x7F, 0x10,   // 4  
0x27, 0x45, 0x45, 0x45, 0x39,   // 5  
0x3C, 0x4A, 0x49, 0x49, 0x30,   // 6  
0x01, 0x71, 0x09, 0x05, 0x03,   // 7  
0x36, 0x49, 0x49, 0x49, 0x36,   // 8  
0x06, 0x49, 0x49, 0x29, 0x1E,   // 9  
0x00, 0x36, 0x36, 0x00, 0x00,   // :  
0x00, 0x56, 0x36, 0x00, 0x00,   // ;  
0x08, 0x14, 0x22, 0x41, 0x00,   // <  
0x14, 0x14, 0x14, 0x14, 0x14,   // =  
0x00, 0x41, 0x22, 0x14, 0x08,   // >  
0x02, 0x01, 0x51, 0x09, 0x06,   // ?  
0x32, 0x49, 0x59, 0x51, 0x3E,   // @  
0x7C, 0x12, 0x11, 0x12, 0x7C,   // A  
0x7F, 0x49, 0x49, 0x49, 0x36,   // B  
0x3E, 0x41, 0x41, 0x41, 0x22,   // C  
0x7F, 0x41, 0x41, 0x22, 0x1C,   // D  
0x7F, 0x49, 0x49, 0x49, 0x41,   // E  
0x7F, 0x09, 0x09, 0x09, 0x01,   // F  
0x3E, 0x41, 0x49, 0x49, 0x7A,   // G  
0x7F, 0x08, 0x08, 0x08, 0x7F,   // H  
0x00, 0x41, 0x7F, 0x41, 0x00,   // I  
0x20, 0x40, 0x41, 0x3F, 0x01,   // J  
0x7F, 0x08, 0x14, 0x22, 0x41,   // K  
0x7F, 0x40, 0x40, 0x40, 0x40,   // L  
0x7F, 0x02, 0x0C, 0x02, 0x7F,   // M  
0x7F, 0x04, 0x08, 0x10, 0x7F,   // N  
0x3E, 0x41, 0x41, 0x41, 0x3E,   // O  
0x7F, 0x09, 0x09, 0x09, 0x06,   // P  
0x3E, 0x41, 0x51, 0x21, 0x5E,   // Q  
0x7F, 0x09, 0x19, 0x29, 0x46,   // R  
0x46, 0x49, 0x49, 0x49, 0x31,   // S  
0x01, 0x01, 0x7F, 0x01, 0x01,   // T  
0x3F, 0x40, 0x40, 0x40, 0x3F,   // U  
0x1F, 0x20, 0x40, 0x20, 0x1F,   // V  
0x3F, 0x40, 0x38, 0x40, 0x3F,   // W  
0x63, 0x14, 0x08, 0x14, 0x63,   // X  
0x07, 0x08, 0x70, 0x08, 0x07,   // Y  
0x61, 0x51, 0x49, 0x45, 0x43,   // Z  
0x00, 0x7F, 0x41, 0x41, 0x00,   // [  
0x55, 0x2A, 0x55, 0x2A, 0x55,   // 55  
0x00, 0x41, 0x41, 0x7F, 0x00,   // ]  
0x04, 0x02, 0x01, 0x02, 0x04,   // ^  
0x40, 0x40, 0x40, 0x40, 0x40,   // _  
0x00, 0x01, 0x02, 0x04, 0x00,   // ’  
0x20, 0x54, 0x54, 0x54, 0x78,   // a  
0x7F, 0x48, 0x44, 0x44, 0x38,   // b  
0x38, 0x44, 0x44, 0x44, 0x20,   // c  
0x38, 0x44, 0x44, 0x48, 0x7F,   // d  
0x38, 0x54, 0x54, 0x54, 0x18,   // e  
0x08, 0x7E, 0x09, 0x01, 0x02,   // f  
0x18, 0xA4, 0xA4, 0xA4, 0x7C,   // g  
0x7F, 0x08, 0x04, 0x04, 0x78,   // h  
0x00, 0x44, 0x7D, 0x40, 0x00,   // i  
0x40, 0x80, 0x84, 0x7D, 0x00,   // j  
0x7F, 0x10, 0x28, 0x44, 0x00,   // k  
0x00, 0x41, 0x7F, 0x40, 0x00,   // l  
0x7C, 0x04, 0x18, 0x04, 0x78,   // m  
0x7C, 0x08, 0x04, 0x04, 0x78,   // n  
0x38, 0x44, 0x44, 0x44, 0x38,   // o  
0xFC, 0x24, 0x24, 0x24, 0x18,   // p  
0x18, 0x24, 0x24, 0x18, 0xFC,   // q  
0x7C, 0x08, 0x04, 0x04, 0x08,   // r  
0x48, 0x54, 0x54, 0x54, 0x20,   // s  
0x04, 0x3F, 0x44, 0x40, 0x20,   // t  
0x3C, 0x40, 0x40, 0x20, 0x7C,   // u  
0x1C, 0x20, 0x40, 0x20, 0x1C,   // v  
0x3C, 0x40, 0x30, 0x40, 0x3C,   // w  
0x44, 0x28, 0x10, 0x28, 0x44,   // x  
0x1C, 0xA0, 0xA0, 0xA0, 0x7C,   // y  
0x44, 0x64, 0x54, 0x4C, 0x44,   // z  
0x00, 0x08, 0x36, 0x41, 0x00,   // {  
0x00, 0x00, 0x7F, 0x00, 0x00,   // |  
0x00, 0x41, 0x36, 0x08, 0x00,   // }  
0x08, 0x10, 0x08, 0x04, 0x08    // ~  
};  
#endif




使用特权

评论回复
地板
panxiaoyi|  楼主 | 2021-2-28 13:54 | 只看该作者


//为了直观和理解还是对寄存器的每个功能位分步操作-------


//数据的某位写1或0


#ifndef _BIT_H_
#define _BIT_H_


#define B7H |= 0x80
#define B6H |= 0x40
#define B5H |= 0x20
#define B4H |= 0x10
#define B3H |= 0x08
#define B2H |= 0x04
#define B1H |= 0x02
#define B0H |= 0x01


#define B7L &= 0x7F
#define B6L &= 0xBF
#define B5L &= 0xDF
#define B4L &= 0xEF
#define B3L &= 0xF7
#define B2L &= 0xFB
#define B1L &= 0xFD
#define B0L &= 0xFE


#endif


//-----------------

使用特权

评论回复
5
panxiaoyi|  楼主 | 2021-2-28 13:55 | 只看该作者


#ifndef __DELAY_H__
#define __DELAY_H__


void delay_us(unsigned long us)
{                        
        unsigned long i;
        i=us;
        while(i--);
}


#endif

使用特权

评论回复
6
panxiaoyi|  楼主 | 2021-2-28 13:56 | 只看该作者
/**
*        1、MCU提供10/12位ADC检测,拥有16路外部输入通道以及2路内部输入通道
*        2、参考电压可选择内部Vref(VDD、2V、3V、4V)以及外部Vref
*        3、在掉电模式下,ADCEN强制为0,ADC失能。
*        4、为保证ADC转换精度,建议ADC转换时钟频率在2MHz及2MHz以下。
*        5、内部参考电压选择2V时,VDD工作电压须高于2.7V。内部参考电压选择3V/4V时,VDD工作电
*           压须高于内部参考电压0.5V以上。
*        6、使能ADC模块或者切换通道后,为保证精度建议延时20us再启动转换。
*        7、启动转换时,ADCIF需要先软件清0,ADCIF位为1时,置ADCST不能启动新的转换。在转换过
*           程中,若ADCST位软件清0将终止转换。
*        8、在进行内部通道选择时,外部通道选择XCHS[3:0]应配置为1111,否则可能会造成内部通道
*           和外部通道同时打开的情况。       
*        9、芯片进入掉电模式时将ADCC0中的INREF_S寄存器设置为非VDD电压,可以进一步降低电流。
* 0、单通道连续扫描模式时扫描次数和NUM(SCANCOM[2-0])值无关。
**/


#ifndef __MCUADC_H__
#define __MCUADC_H__
#include <BIT.h>


void ADC_init(void)
{
        P0M7=0;                 //选择内部VREF输出时,引脚必须设为模拟输入
        P0M6=0;                 //ADC输入通道,必须设置为模拟输入
        P0M5=0;                 //ADC输入通道
       
        ADCC0=0;                //Bit6是开始启动,Bit5是中断标记,Bit4保留
        ADCC0 B7H;              //打开ADC电源
        ADCC0 B3H;              //内部VREF输出使能(观察用途或者接滤波电容)
        ADCC0 B2L;              //内部VREF,=1是外部
        ADCC0 B1L;              //Bit1与Bit0组合为设置内部参考电压
        ADCC0 B0L;              //00=VDD,01=4V,10=3V,11=2V
        ADCC2 |=1;              //ADC时钟 0-7 = 2,4,6,...,128分频(一次转换需15个ADC时钟)
}


unsigned char ADC_read8(unsigned char ADC_IO) //启动转换并读取某通道的8位ADC
{
        unsigned char dat;
        ADCC2 B7L;              //0=12Bit,1=10Bit
        ADCC2 B6L;              //数据对齐方式(********0000****)
        ADCC1 = ADC_IO;         //通道选择
        ADCC0 |= 0x40;                                        //启动ADC转换
        while(!(ADCC0&0x20));                //等待ADC转换结束
        ADCC0 &=~ 0x20;                                        //清除标志位
        dat = ADCRH;
        return dat;
}


unsigned int ADC_read16(unsigned char ADC_IO) //启动转换并读取某通道的12位ADC
{
        unsigned int dat;
        ADCC2 B7L;              //0=12Bit,1=10Bit
        ADCC2 B6H;              //数据右对齐(0000************)
        ADCC1 = ADC_IO;         //通道选择
        ADCC0 |= 0x40;                                        //启动ADC转换
        while(!(ADCC0&0x20));                //等待ADC转换结束
        ADCC0 &=~ 0x20;                                        //清除标志位
        dat = ADCRH;
        dat <<= 8;
        dat = dat+ADCRL;
        return dat;
}


#endif

使用特权

评论回复
7
panxiaoyi|  楼主 | 2021-2-28 13:57 | 只看该作者


#ifndef __MCUIIC_H__
#define __MCUIIC_H__


//软件模拟 IIC 主机发送


sbit IIC_SCL=P2^5;                 //SCL
sbit IIC_SDA=P2^6;                 //SDA


//简单延时
void IIC_delay_us(void)
{
        unsigned char i=0;               //软件延时时间0123456...
        while(i) i--;
}


//IIC初始化
void IIC_init(void)
{
  P2M5 = 0xC0;                     //推换输出,开漏上拉输出太弱了容易受干扰
        P2M6 = 0xC0;
       
        IIC_SCL=1;                       //时钟数据STOP
        IIC_delay_us();
        IIC_SDA=1;
        IIC_delay_us();
}


//主机发起起始信号
void IIC_start(void)
{
        IIC_SDA=0;
        IIC_delay_us();
        IIC_SCL=0;
        IIC_delay_us();
}


//向接收方写入一个字节
void IIC_write(unsigned char dat)
{
        unsigned char i;
        for(i=0;i<8;i++)
        {
                if(dat&0x80) IIC_SDA=1; else IIC_SDA=0;
    IIC_delay_us();
                IIC_SCL=1;
                IIC_delay_us();
                IIC_SCL=0;
                IIC_delay_us();
                dat<<=1;
  }
        //模拟接收ACK
  IIC_SDA=0;                       //建议ACK是0,防止与其它器件短路
        IIC_delay_us();
        IIC_SCL=1;
        IIC_delay_us();
        IIC_SCL=0;
        IIC_delay_us();
        IIC_SDA=0;
        IIC_delay_us();
}


//写人接收方地址。有利于兼容硬件IIC
void IIC_write_addr(unsigned char addr)
{
        IIC_write(addr);
}


//结束信号
void IIC_stop(void)
{
        IIC_SCL=1;
        IIC_delay_us();
        IIC_SDA=1;
        IIC_delay_us();
}


#endif

使用特权

评论回复
8
panxiaoyi|  楼主 | 2021-2-28 13:59 | 只看该作者


#ifndef __SH1106_H__
#define __SH1106_H__


#include <DELAY.h>
#include <0805FONT.h>
#include <MCUIIC.h>


//SSD1306(12864)的列显示从列地址0开始
//SH1106 (13264)的列显示从列地址2开始
//坐标设置
void OLED_gotoxy(unsigned char x0, unsigned char y)
{
        unsigned char x;
        x=x0+2;                                          
        IIC_start();
        IIC_write_addr(0x78);
  IIC_write(0x00);
        IIC_write(0xb0+y);
        IIC_write(((x&0xf0)>>4)|0x10);
        IIC_write((x&0x0f));
        IIC_stop();
}             
                                    
//清屏
void OLED_Clear(void)  
{  
        unsigned char i,n;                    
        for(i=0;i<8;i++)  
        {  
                IIC_start();
          IIC_write_addr(0x78);                          //高7位器件地址+1位R/W
    IIC_write(0x00);                               //准备写指令
                IIC_write(0xb0+i);                             //设置页地址(0~7)
                IIC_write(0x00);                               //设置显示位置—列低地址
                IIC_write(0x10);                               //设置显示位置—列高地址
                IIC_stop();                                    //实践证明此句不能省略,否则无法清屏
                IIC_start();                                   //再次启动START是为了指令与数据的切换
          IIC_write(0x78);
          IIC_write(0x40);                               //准备写数据
                for(n=0;n<132;n++) IIC_write(0);               //兼容128和132点阵
                IIC_stop();
        }
}


//=====================================================================================


void OLED_code(unsigned char dat)                  //将ASCII表的代码以字符的方式显示  
{     
  unsigned char i=0;  
  unsigned int No;  
  No=dat-32;                                       //字模数据是由空格开始,空格字符的ASCII的值就是32  
  No=No*5;                                         //每个字符的字模是5个字节  


        IIC_start();
        IIC_write_addr(0x78);
        IIC_write(0x40);


  while(i<5)                                       //一个字符的字模是5个字节,就是5*8点阵  
     {  
       IIC_write(FONT__0805[No]);
       i++;  
       No++;  
     }  
  IIC_write(0);                                    //每个字符之间空一列  
        IIC_stop();
}   


//=====================================================================================  


void OLED_string(unsigned char *s)                 //字符串函数/C编译器会在字符串后面加\0
{
        while(*s)                                        //检测字符串结束符
    {
                        OLED_code(*s++);
    }
}      


//=======================================================================================  


void OLED_show(unsigned int dat)                   //显示最大16位变量/负数可以先乘以负1
{
        unsigned int i;
  for(i=10000; i>=1; i=i/10)
        {
    OLED_code(dat/i%10+0x30);
  }
}   


//初始化                                    
void OLED_init(void)
{
  delay_us(9999);
        IIC_start();
        IIC_write_addr(0x78);//总线OLED地址
                IIC_write(0x00);//准备写指令
        IIC_write(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
        IIC_write(0x81);//双字节指令,亮度
        IIC_write(0x05);//亮度 0-FF
        IIC_write(0xA1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
        IIC_write(0xC8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
        IIC_write(0xA8);//--set multiplex ratio(1 to 64)
        IIC_write(0x3f);//--1/64 duty
        IIC_write(0xD3);//-set display offset        Shift Mapping RAM Counter (0x00~0x3F)
        IIC_write(0x00);//-not offset
        IIC_write(0xd5);//--set display clock divide ratio/oscillator frequency
        IIC_write(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
        IIC_write(0xD9);//--set pre-charge period
        IIC_write(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
        IIC_write(0xDA);//--set com pins hardware configuration
        IIC_write(0x12);
        IIC_write(0xDB);//--set vcomh
        IIC_write(0x40);//Set VCOM Deselect Level
        IIC_write(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
        IIC_write(0x02);//
        IIC_write(0x8D);//--set Charge Pump enable/disable
        IIC_write(0x14);//--set(0x10) disable
        IIC_write(0xA4);//正常,全亮 (0xa4/0xa5)
        IIC_write(0xA6);// Disable Inverse Display On (0xa6/a7)
        IIC_write(0xC0);//180`
        IIC_write(0xA0);//180`
        IIC_write(0xC8);//0`
        IIC_write(0xA1);//0`       
        IIC_write(0xA6);//正常A6,反显A7
        IIC_write(0xAF);//关闭AE,显示AF
        IIC_stop();
}


#endif  


使用特权

评论回复
9
panxiaoyi|  楼主 | 2021-2-28 14:04 | 只看该作者


#ifndef __MCUPWM_H__
#define __MCUPWM_H__
#include <BIT.h>


#define PWM3_RATIO 100  //计数周期,占空比寄存器的数值不能大于它


void PWM3_init(void)
{
        PWM3C B7H;                              //打开PWM3,8位
        PWM3C B6L;                              //中断禁止
        PWM3C B5L;                              //中断标记清零
        PWM3C B4H;                              //允许输出
        PWM3C B3L;                              //占空正比例
        PWM3C B2L;                              //Bit 2 1 0 是时钟设置,默认000=Fosc/1
        PWM3C B1L;                              //001=Fosc/2,010=Fosc/4,011=Fosc/8
        PWM3C B0L;                              //以此类推,最高 111=Fosc/128
        PWM3P=PWM3_RATIO;                       //数值越小PWM频率越高,但是占空比分辨率就越小
        PWM3_MAP=0x30;                          //PWM输出映射到该脚
        P3M0=0xC0;                              //推换输出
}


void PWM3_ratio(unsigned char ratio)
{
        if(ratio>PWM3_RATIO) ratio=PWM3_RATIO;
        PWM3D=ratio;                            //调整占空比
}


#endif

使用特权

评论回复
10
panxiaoyi|  楼主 | 2021-2-28 14:41 | 只看该作者
磁悬浮刚刚好用到上面的程序,下面这个磁悬浮是我之前使用 AVR 的 ATtiny13 制作的

https://bbs.21ic.com/icview-3069754-1-1.html

使用特权

评论回复
11
zhengshuai888| | 2021-3-1 12:30 | 只看该作者
谢谢楼主分享经验

使用特权

评论回复
12
单片小菜| | 2021-3-3 14:45 | 只看该作者
感谢楼主的分享,这个确实不错的应用的。

使用特权

评论回复
13
里面有晴雨| | 2021-3-3 19:23 | 只看该作者
期待楼主有更好的作品,我也有一个差不多的开发板,也想玩玩。

使用特权

评论回复
14
lidi911| | 2021-3-3 21:09 | 只看该作者
谢谢楼主分享

使用特权

评论回复
15
yzq13246068880| | 2021-3-4 10:55 | 只看该作者

使用特权

评论回复
16
名字是啥样| | 2021-3-4 16:33 | 只看该作者
这个驱动感觉是万能的驱动。

使用特权

评论回复
17
panxiaoyi|  楼主 | 2021-3-4 20:44 | 只看该作者
因为我也喜欢玩AVR,所以,程序都尽量兼顾移植的方便,下面的代码做了微调,更方便移植,AVR与51互转非常的方便

HC8051 ADC PWM3 IIC SH1106 OLED.rar

56.26 KB

ATmega48 ADC PWM2 IIC SH1106 OLED.rar

58.36 KB

使用特权

评论回复
18
便携手到老| | 2021-3-5 18:28 | 只看该作者
现在能够踏实做底层的人,越来越少了。

使用特权

评论回复
19
1123506| | 2022-3-24 15:13 | 只看该作者
上海芯圣一级代理 出芯圣IC   需要联系企鹅号  2914373240

使用特权

评论回复
20
asmine| | 2022-3-25 15:01 | 只看该作者
不错的,真棒啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

393

帖子

2

粉丝