目录
1、烧录
2、数码管—共阳极
3、按键—长按+短按
4、串口通信—TXD+RXD
5、ADC
6、总结
1、烧录
烧录环境:STC-ISP(善用这个软件,里面有STC系列芯片丰富的示例程序)
烧录工具:使用usb转ttl模块(CH340)
烧录过程:将TXD、RXD、GND都接好后,先不接5V,连上电脑,识别到串口后,打开程序文件(之前要生成hex文件),点击下载/编程,这时程序显示正在检测单片机,然后把5V接到单片机,程序就烧录成功了。
要注意区别共阳和共阴的区别。
这里以共阳极为例。
原理:浅薄的来说一下我自己的理解,一个数码管主要由位选和段选来控制。
对于一位(即一个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里,以及丰富的例程都给我提供了非常多的帮助。
推荐给大家。
如果需要完整的项目资源可以等我上传了去下载哦。
未完待续...
感谢指导!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)