【项目】STC15W408AS--烧写、数码管、按键、串口通信、ADC

【项目】STC15W408AS--烧写、数码管、按键、串口通信、ADC,第1张

目录

1、烧录

2、数码管—共阳极

3、按键—长按+短按

4、串口通信—TXD+RXD

5、ADC

6、总结


1、烧录

烧录环境:STC-ISP(善用这个软件,里面有STC系列芯片丰富的示例程序)

烧录工具:使用usb转ttl模块(CH340)

烧录过程:将TXD、RXD、GND都接好后,先不接5V,连上电脑,识别到串口后,打开程序文件(之前要生成hex文件),点击下载/编程,这时程序显示正在检测单片机,然后把5V接到单片机,程序就烧录成功了。


2、数码管—共阳极 电路

要注意区别共阳和共阴的区别。


这里以共阳极为例。


原理:浅薄的来说一下我自己的理解,一个数码管主要由位选和段选来控制。


对于一位(即一个8)而言,我们将它所有led的阳极都连接在一起,这一端即位选,用于接5V电路,即上图的DIG1。


然后我们把led的阴极与单片机引脚相连接,这一端即段选,即A、B、C...当单片机引脚输出0,led的阳极到阴极导通,led发光,数码管亮,这就是共阳极数码管基本的运行原理。


R19、R20、R21的作用:?

R13~R18..的作用:?(应该都是起到保护作用吧)

一个建议:最好将8位段选都放在mcu的一个口上,如P2口,这样写程序的时候方便点。


代码
#include "led.h"
​
u8 table[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
//显示0~F
​
//位选
sbit dig1=P3^4;
sbit dig2=P3^3;//十位
sbit dig3=P3^2;//个位
​
​
//数码管显示
void display(u16 i){
​
    u16 ge = i%10;
    u16 shi = i%100/10;
    u16 bai = i/100;
    
    //显示个位
    dig1 =1;
    dig2 =1;
    dig3 =0;
    show(ge);
    delay(5);
    
    //显示十位
    dig1 =1;
    dig2 =0;
    dig3 =1;
    show(shi);
    delay(5);
    
    //显示百位
    dig1 =0;
    dig2 =1;
    dig3 =1;
    show(bai);
    delay(5);
}
​
​
void show(u16 i){   
    P2 = table[i];
}
--------------------------------------------------------------------
#ifndef __LED_H
#define __LED_H
​
#include 
#include "global.h"
​
//#define uchar unsigned char
//#define uint unsigned int
​
extern u8 table[16];
​
​
//void delay(u16 z);
void display(u16 i);
void show(u16 i); 
​
#endif

3、按键—长按+短按 电路

蛮简单的,只要单片机有个口去检测电平变化即可,我是接到外部中断口上去了,在下降沿的时候触发按键的判断,都可以。


(CHECK_KEY)

代码

因为在检测按键的时候,数码管也需要同时运行,所以不能简单的在函数里加个delay来延时,这样会导致进程阻塞,数码管不工作,所以我把按键判断放在了定时器中断里(定时器0在这个程序中是一直在跑着的)赋值key,然后去做相应的动作。


//定时器0中断服务程序-按键   5毫秒@11.0592MHz (实际是50ms左右)
void tm0_isr() interrupt 1
{
        extern u16 KEY_PIN;
        if(KEY_PIN)
        {
            key_count2++;//本意是消抖,但这里好像有点多余,可能条件换成P37==0更好
        }
        if(key_count2>=2)
        {           
            if(P37 == 0)
            {
                press_flag = 1;
                KEY_COUNT++;
            }
            else
            {                       
                    if(press_flag)
                    {
                        if(KEY_COUNT>=60)
                        {
                            KEY_COUNT = 0;
                            press_flag = 0;
                            key = 0;    //长按
                            KEY_PIN = 0;
                            key_count2 = 0;                     
                        }
                        else
                        {
                            KEY_COUNT = 0;
                            press_flag = 0;
                            key = 1;    //短按    
                            KEY_PIN = 0;    
                            key_count2 = 0;
                        }           
                    }
            }           
        }
}
/*外部中断3仅下降沿可以触发。


外部中断2~3的中断请求标志位被隐藏起来了,对用户不可见,故也无需用户清"0"。


当相应的中断服务程序被响应后或中断允许位EXn (n=2,3)被清零后, 这些中断请求标志位会立即自动地被清0。


*/ //----------------------------------------------- //外部中断3服务程序(仅下降沿触发) void exint3() interrupt 11          //INT3中断入口 { extern u16 KEY_PIN; KEY_PIN = 1; ​ // INT_CLKO &= 0xDF;               //若需要手动清除中断标志,可先关闭中断,此时系统会自动清除内部的中断标志 // INT_CLKO |= 0x20;               //然后再开中断即可 } //定时器初始化 #define FOSC 11059200L #define T5MS (65536-5*FOSC/1000)    //1T模式,110592MHz INT_CLKO |= 0x20;               //(EX3 = 1)使能INT3中断,仅下降沿触发 AUXR |= 0x80;  //定时器时钟1T模式 (定时器0的速度是传统8051的12倍,不分频) //AUXR &= 0x7f;       //定时器0为12T模式 TMOD &= 0xF0;  //设置定时器模式(16位自动重装定时器) TL0 = T5MS;           //初始化计时值 TH0 = T5MS >> 8; TF0 = 0;  //清除TF0标志(溢出中断标志) TR0 = 1;  //定时器0开始计时 ET0 = 1;      //使能定时器0中断 EA = 1;  //打开总中断

4、串口通信—TXD+RXD 电路

代码

也差不多都是例程里的代码,具体怎么实现就看你自己啦。


#include "uart.h"
​
#define FOSC    11059200L
#define BAUD    115200
​
#define     URMD    0           //0:使用定时器2作为波特率发生器
                                //1:使用定时器1的模式0(16位自动重载模式)作为波特率发生器
                                //2:使用定时器1的模式2(8位自动重载模式)作为波特率发生器  
​
/*----------------------------
初始化串口
----------------------------*/
void InitUart()
{
    SCON = 0x5a;                //设置串口为8位可变波特率
#if URMD == 0
    T2L = (65536 - (FOSC/4/BAUD));
    T2H = (65536 - (FOSC/4/BAUD)) >> 8;
    AUXR = 0x14;                //T2为1T模式, 并启动定时器2
    AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器
        ES = 1;                     //使能串口1中断
#elif URMD == 1
    AUXR = 0x40;                //定时器1为1T模式
    TMOD = 0x00;                //定时器1为模式0(16位自动重载)
    TL1 = (65536 - (FOSC/4/BAUD)); //设置波特率重装值
    TH1 = (65536 - (FOSC/4/BAUD)) >> 8;
    TR1 = 1;                    //定时器1开始启动
#else
    TMOD = 0x20;                //设置定时器1为8位自动重装载模式
    AUXR = 0x40;                //定时器1为1T模式
    TH1 = TL1 = (256 - (FOSC/32/BAUD));
    TR1 = 1;
#endif
}
​
/*----------------------------
发送串口数据
----------------------------*/
void SendData(u8 dat)
{
    SBUF = dat;                     //发送当前数据
      while (!TI);                    //等待前一个数据发送完成
    TI = 0;                         //清除发送标志
​
}
​
/*************************************************
 *函数名称:void Uart() interrupt 4 using 1                                  
 *功    能:串口中断处理函数                                      
 *参    数:void                                       
 *返 回 值:void                                       
 *************************************************/
void Uart() interrupt 4 using 1
{
        //接收中断标志
        if(RI)
        {
            RI = 0;                 //清除RI位
            ReceiveBuf = SBUF;
            if(ReceiveDone == 0)
            {
                    
            }               
        }
    
        //发送中断标志
    if (TI) //8位数据发送结束 会请求中断
    {
       TI = 0;                 //清除TI位
       // busy = 0;               //清忙标志
    }
}

5、ADC 电路:

代码

获取ADC结果后就可以按你需要的想法去 *** 作了。


它返回的结果是内部已经计算好的,公式大概记得是256*(vin/vcc)。


参考电压是你的电源电压。


#include "adc.h"
#include "intrins.h"
​
/* --- STC15F4K60S4 系列 AD转换查询方式举例----------------------------*/
​
                    
​
#define ADC_POWER   0x80            //ADC电源控制位
#define ADC_FLAG    0x10            //ADC完成标志
#define ADC_START   0x08            //ADC起始控制位
#define ADC_SPEEDLL 0x00            //540个时钟周期转换一次,模数转换器转换速度控制位
#define ADC_SPEEDL  0x20            //360个时钟
#define ADC_SPEEDH  0x40            //180个时钟
#define ADC_SPEEDHH 0x60            //90个时钟
​
/*----------------------------
读取ADC结果
----------------------------*/
u8 GetADCResult(u8 ch)
{
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
    _nop_();                        //等待4个NOP
    _nop_();
    _nop_();
    _nop_();
    while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
    ADC_CONTR &= ~ADC_FLAG;         //Close ADC,ADC_FLAG清零
​
    return ADC_RES;                 //返回ADC结果(256*(vin/vcc))
}
​
​
/*----------------------------
初始化ADC
----------------------------*/
void InitADC()
{
    P1ASF = 0xc0;                   //设置P1口为AD口 (设置p1.0和p1.1口为ad口)
    ADC_RES = 0;                    //清除结果寄存器
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
    Delay(2);                       //ADC上电并延时
}

6、总结

从选型到全部跑通,这个小项目大概做了一个月,第一次上手51单片机(本科学过但已经很模糊了)很感谢自己选了STC这个品牌,虽然看它的官网看着非常的难以言喻(没有不好的意思),但它的上位机做的是真的好,stc-isp,基本上从单片机的选型、添加型号到keil里,以及丰富的例程都给我提供了非常多的帮助。


推荐给大家。


如果需要完整的项目资源可以等我上传了去下载哦。


未完待续...

感谢指导!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/585074.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存