蓝桥杯单片全模块模板详解
1.基础外设模块
注意事项:LED(低电平点亮),数码管,蜂鸣器,继电器,都需要在使能后才能使用。整体操作和位操作选一个即可
LED部分:
实验现象:L1以100ms的间隔闪烁
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
u8 time_100ms;
bit L1, L2, L3, L4; // LED 位操作
// LED 使能, 操作 LED 前都需要使能, 根据响应速度决定是否放中断里
void led_enable() {
P0 = 0xFF; // 关闭所有 LED
P2 = 0x80; // 控制 LED 端口
P00 = L1;
P01 = L2;
P02 = L3;
P03 = L4; /* 单个LED控制-适用于状态指示灯和单个LED灯闪烁 */
P2 = 0x00; // 清除控制端口
}
/* 使用:一般放在中断,不断使能 */
// 定时器1初始化函数
void Timer1_Init(void) // 1毫秒@12.000MHz
{
AUXR |= 0x40; // 定时器时钟1T模式
TMOD &= 0x0F; // 设置定时器模式
TL1 = 0x20; // 设置定时初始值
TH1 = 0xD1; // 设置定时初始值
TF1 = 0; // 清除TF1标志
TR1 = 1; // 定时器1开始计时
ET1 = 1; // 使能定时器1中断
}
int main(void) {
Timer1_Init();
EA = 1;
while (1) {
}
}
// 定时器1中断服务函数
void Timer1_Isr(void) interrupt 3 {
led_enable();
if (++time_100ms >= 100) {
time_100ms = 0;
L1 = ~L1;
}
}
蜂鸣器继电器部分:
#include <STC15F2K60S2.H>
sbit relay = P0^4; // 定义继电器引脚-在函数外定义
sbit buzzer = P0^6; // 定义蜂鸣器引脚
//高电平响应
void relay_enable_control(bit io_level)
{
P2=0XA0; //打开继电器输出
relay = io_level; //
P2=0X00; //失能继电器输出
}
//高电平响应
void buzzer_control(bit io_level) {
P2 = 0xA0; // 使能蜂鸣器输出
buzzer = io_level; // 控制蜂鸣器电平
P2 = 0x00; // 失能蜂鸣器输出
}
int main(void)
{
P2=0X80;P0=0XFF;P2=0X00;
P2=0XA0;P0=0X00;P2=0X00;
while (1)
{
//buzzer_control(1); // 控制蜂鸣器
//relay_enable_control(0);//控制继电器
}
}
数码管部分:
段码表不需要记,在stc-isp中的数码管范例中有 实验现象:num一直以1ms+1的速度自增.直到加到65535重新变成0
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
// 数码管刷新周期计数器,8位,每个周期 1ms,总周期 8ms
static u8 time_8ms = 0;
// 数码管显示数据缓存,每一位对应一个数码管的显示内容
static u8 SMG[8];
// 待显示数字
volatile u16 num;
// 标准字符显示代码(共阴极数码管),这个不用记
static u8 code t_display[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71,
0x00, 0x40, 0x76, 0x1E, 0x70, 0x38, 0x37, 0x5C,
0x73, 0x3E, 0x78, 0x3D, 0x67, 0x50, 0x37, 0x6E,
0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87,
0xFF, 0xEF, 0x46
};
// 位选控制代码,用于选择哪个数码管被点亮
static u8 code T_COM[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
// 数码管显示函数,控制指定位显示指定的段码
// wei: 位选择,范围 0-7,对应 T_COM 数组
// duan: 段码选择,范围 0-52,对应 t_display 数组
void smg_enable_control(u8 wei, u8 duan) {
P0 = 0xFF; // 关闭所有段码,避免残影
P2 = 0xC0; P0 = T_COM[wei]; P2 = 0x00; // 选择数码管位
P2 = 0xE0; P0 = ~t_display[duan]; P2 = 0x00; // 显示段码数据 (共阴极数码管需要取反)
}
// 将 num 的值分解并存储到 SMG 数组中,准备显示
void num_show(void)
{
// 初始化所有数码管显示为空 (16 对应 t_display 中的 0x00, 即不显示)
SMG[0] = 16;
SMG[1] = 16;
SMG[2] = 16;
SMG[3] = num / 10000; // 万位
SMG[4] = num / 1000 % 10; // 千位
SMG[5] = num / 100 % 10; // 百位
SMG[6] = num / 10 % 10; // 十位
SMG[7] = num % 10; // 个位
}
// 定时器1初始化函数,配置为 1ms 中断
void Timer1_Init(void)
{
AUXR |= 0x40; // 定时器时钟 1T 模式
TMOD &= 0x0F; // 设置定时器模式,仅修改 T1 的模式位
TL1 = 0x20; // 设置定时初始值
TH1 = 0xD1; // 设置定时初始值
TF1 = 0; // 清除 TF1 标志
TR1 = 1; // 定时器1开始计时
ET1 = 1; // 使能定时器1中断
}
int main(void)
{
Timer1_Init(); // 初始化定时器1
EA = 1; // 开启全局中断
while(1)
{
num_show(); // 更新数码管显示数据
}
}
// 定时器1中断服务函数
void Timer1_Isr(void) interrupt 3
{
if (++time_8ms == 8) // 每8次中断 (8ms) 更新一次数码管显示
{
time_8ms = 0; // 重置计数器
}
smg_enable_control(time_8ms, SMG[time_8ms]); // 动态显示,更新数码管
++num; // 递增显示数字
}
2.按键
矩形按键:J5需要短接到矩形键盘
实验现象:按S5num+1,短时间内双击S9num+1,长按S9num以50ms+1速度自增,长按s4和s8到达2s以上num清零
#include <STC15F2K60S2.H>
#include "intrins.h"
#define u8 unsigned char
#define u16 unsigned int
bit key_line;
bit long_flag,short_flag,two_flag;
static u8 time_8ms = 0;
static u8 SMG[8];
u8 short_cnt;
u8 time_15ms;
u8 time_50ms;
u16 time_long,time_short,time_two;
// 待显示数字
volatile u16 num;
// 标准字符显示代码(共阴极数码管),这个不用记
static u8 code t_display[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71,
0x00, 0x40, 0x76, 0x1E, 0x70, 0x38, 0x37, 0x5C,
0x73, 0x3E, 0x78, 0x3D, 0x67, 0x50, 0x37, 0x6E,
0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87,
0xFF, 0xEF, 0x46
};
// 位选控制代码,用于选择哪个数码管被点亮
static u8 code T_COM[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void smg_enable_control(u8 wei, u8 duan) {
P0 = 0xFF;
P2 = 0xC0; P0 = T_COM[wei]; P2 = 0x00;
P2 = 0xE0; P0 = ~t_display[duan]; P2 = 0x00;
}
void num_show(void)
{
SMG[0] = 16;
SMG[1] = 16;
SMG[2] = 16;
SMG[3] = num / 10000; // 万位
SMG[4] = num / 1000 % 10; // 千位
SMG[5] = num / 100 % 10; // 百位
SMG[6] = num / 10 % 10; // 十位
SMG[7] = num % 10; // 个位
}
void key_task()
{
num_show();
}
void key_work(void)
{
if(key_line)
{
P32=0;P33=1;P44=1;P42=1;
if(P44==0) //S5
{
while(!P44){key_task(); _nop_();}
++num; //单击
}
if(P42==0) //S9
{
while(!P42){long_flag=1; key_task();}
long_flag=0;short_flag=1;
if(++short_cnt==2){num++;short_cnt=0;}
}
}
else
{
P32=1;P33=0;P44=1;P42=1;
if(P44==0) //S4
{
while(!P44){key_task();if(P42==0)two_flag=1;}
two_flag=0;
}
if(P42==0) //S8
{
while(!P42){key_task();if(P44==0)two_flag=1;}}
two_flag=0;
}
}
void Timer1_Init(void)
{
AUXR |= 0x40; // 定时器时钟 1T 模式
TMOD &= 0x0F; // 设置定时器模式,仅修改 T1 的模式位
TL1 = 0x20; // 设置定时初始值
TH1 = 0xD1; // 设置定时初始值
TF1 = 0; // 清除 TF1 标志
TR1 = 1; // 定时器1开始计时
ET1 = 1; // 使能定时器1中断
}
int main(void)
{
Timer1_Init(); // 初始化定时器1
EA = 1; // 开启全局中断
while(1)
{
key_work();
num_show();
}
}
// 定时器1中断服务函数
void Timer1_Isr(void) interrupt 3
{
if (++time_8ms == 8) // 每8次中断 (8ms) 更新一次数码管显示
{
time_8ms = 0; // 重置计数器
}
smg_enable_control(time_8ms, SMG[time_8ms]); // 动态显示,更新数码管
if(++time_15ms>20){time_15ms=0;key_line=~key_line;}
//长按
if(long_flag)
{
if(time_long<=1000)time_long++;
else{if(++time_50ms>=50){num++;time_50ms=0;}}
}
else time_long=0;
//双击
if(short_flag){if(++time_short>=300){short_flag=0;short_cnt=0;}}
else time_short=0;
//双长按
if(two_flag)
{
if(time_two<=2000){time_two++;}
else num=0;
}
else time_two=0;
}
3.超声波模块
为了不占用其他定时器资源,超声波模块使用PCA模块,具体可以自己搜,读取大概500ms,视情况而定,我这里为了灵敏取20ms 使用时需要将J2的1-3 2-4短接
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
// 使用PCA模块
#define TX P10
#define RX P11
// 数码管刷新周期计数器,8位,每个周期 1ms,总周期 8ms
u8 time_8ms = 0;
// 数码管显示数据缓存,每一位对应一个数码管的显示内容
u8 SMG[8];
u8 distance;
u8 time_20ms;
void PCA_Init(void) // 12微秒@12.000MHz
{
AUXR &= 0x7F; // 定时器时钟12T模式
CMOD &= 0xF0; // 设置定时器模式
CL = 0xF4; // 设置定时初值
CH = 0xFF; // 设置定时初值
CF = 0; // 清除TF0标志
CR = 1; // 定时器0开始计时
}
unsigned char distance_measure(void)
{
unsigned char d, a = 10;
TX = 0; // 关闭发送脉冲
CF = 0XF4;
CH = 0XFF;
CR = 1;
while (a--) // 发送10个脉冲
{
while (!CF); // 等待溢出
TX ^= 1; // 开始发送脉冲
CF = 0; // 清除溢出标志位
}
CR = 0; // 关闭定时器1
CH = 0; // 高位清0
CL = 0; // 低位清0
CR = 1; // 打开计时器
while (RX && !CF) ; // 当RX接受到脉冲或者TF1溢出时继续
if (CF == 1)
{
CF = 0;
d = 255;
} // 关闭定时器1//溢出时距离为无穷大255
else
{
d = ((CH << 8) + CL) * 0.017; // 根据公式计算实际距离
}
CR = 0;
return d;
}
// 标准字符显示代码(共阴极数码管),这个不用记
u8 code t_display[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x00, 0x40, 0x76, 0x1E,
0x70, 0x38, 0x37, 0x5C, 0x73, 0x3E, 0x78, 0x3D, 0x67, 0x50,
0x37, 0x6E, 0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87,
0xFF, 0xEF, 0x46
};
// 位选控制代码,用于选择哪个数码管被点亮
u8 code T_COM[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void smg_enable_control(u8 wei, u8 duan)
{
P0 = 0xFF; // 关闭所有段码,避免残影
P2 = 0xC0;
P0 = T_COM[wei];
P2 = 0x00; // 选择数码管位
P2 = 0xE0;
P0 = ~t_display[duan];
P2 = 0x00; // 显示段码数据 (共阴极数码管需要取反)
}
void num_show(void)
{
SMG[0] = 13;
SMG[1] = 16;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = 16;
SMG[5] = distance / 100; // 百位
SMG[6] = distance / 10 % 10; // 十位
SMG[7] = distance % 10; // 个位
}
void Timer1_Init(void)
{
AUXR |= 0x40; // 定时器时钟1T模式
TMOD &= 0x0F; // 设置定时器模式,仅修改 T1 的模式位
TL1 = 0x20; // 设置定时初始值
TH1 = 0xD1; // 设置定时初始值
TF1 = 0; // 清除 TF1 标志
TR1 = 1; // 定时器1开始计时
ET1 = 1; // 使能定时器1中断
}
int main(void)
{
P2 = 0X80;
P0 = 0XFF;
P2 = 0X00;
P2 = 0XC0;
P0 = 0XFF;
P2 = 0X00;
Timer1_Init(); // 初始化定时器1
PCA_Init();
EA = 1; // 开启全局中断
while (1)
{
if (time_20ms > 20)
{
distance = distance_measure();
time_20ms = 0;
}
num_show();
}
}
void Timer1_Isr(void) interrupt 3
{
if (++time_8ms == 8) // 每8次中断 (8ms) 更新一次数码管显示
{
time_8ms = 0; // 重置计数器
}
smg_enable_control(time_8ms, SMG[time_8ms]); // 动态显示,更新数码管
++time_20ms;
}
4.IIC部分
ADC:在中断中读取(大约间隔200ms) 光敏电阻地址(0X01或者0X41)可调电阻地址(0X03或者0X43)不能同时读取,如果同时采集俩个电阻的电压,则地址需要互换 因为采集的都是上一次转换的结果,并间隔一段时间 DAC:在中断中输出(也是大约间隔200ms)
**注意事项:在比赛中只给出iic.c,需要自己添加iic.h。*并且底层驱动也不给出引脚定义,Delay部分也需要自己修改
实验现象:有五个界面,按S5进行切换,第一个界面是AIN1也就是光敏电阻采集,第二个界面是AIN3也就是电阻分压采集(RB2),第三个界面是DAC输出电压,1.00为1V,第四个界面是eeprom(24c02)写入的数据(地址为0x00),第五个界面是eeprom读取的数据(地址为0x00)(这个地址的数据上电就会读取) 按下S9write_num会自增,按下s4就会写入数据,按下s8就会读取写入的数据
iic.c
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "iic.h"
sbit sda=P2^1;
sbit scl=P2^0;
#define DELAY_TIME 5
//自己修改nop的数量
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();//一般是这么多_nop_
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
void Delay5ms(void) //@12.000MHz
{
unsigned char data i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
unsigned char dac(unsigned char dat)
{
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x43);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
return dat;
}
unsigned char adc(unsigned char addr)
{
unsigned char temp;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
temp=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return temp;
}
void write_24c02(unsigned char addr,unsigned char dat)//不能连续写入,需要间断5ms
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
Delay5ms();
}
unsigned char read_24c02(unsigned char addr)
{
unsigned char temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
temp=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return temp;
}
iic.h
#ifndef __ICC_H__
#define __ICC_H__
unsigned char dac(unsigned char dat);
unsigned char adc(unsigned char addr);
void write_24c02(unsigned char addr,unsigned char dat);//不能连续写入,需要间断5ms
unsigned char read_24c02(unsigned char addr);
#endif
main.c
#include <STC15F2K60S2.H>
#include "iic.h"
#include "intrins.h"
#define u8 unsigned char
#define u16 unsigned int
bit key_line;
bit long_flag,short_flag,two_flag;
u8 time_8ms,time_15ms,time_200ms;
u8 SMG[8];
u8 show_mode;
u8 adc_chan1,adc_chan3;
u8 write_num,read_num;
u16 voltage;
u8 code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
u8 code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
void smg_enable_control(u8 wei, u8 duan) {
P0 = 0xFF;
P2 = 0xC0; P0 = T_COM[wei]; P2 = 0x00;
P2 = 0xE0; P0 = ~t_display[duan]; P2 = 0x00;
}
void A1_show(void)
{
SMG[0] = 10;
SMG[1] = 1 ;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = 16;
SMG[5] = adc_chan1/100;
SMG[6] = adc_chan1/10%10;
SMG[7] = adc_chan1%10;
}
void A3_show(void)
{
SMG[0] = 10;
SMG[1] = 3 ;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = 16;
SMG[5] = adc_chan3/100;
SMG[6] = adc_chan3/10%10;
SMG[7] = adc_chan3%10;
}
void Voltage_show(void)
{
SMG[0] = 25;
SMG[1] = 16 ;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = 16;
SMG[5] = voltage/100;
SMG[6] = voltage/10%10+32;
SMG[7] = voltage%10;
}
void readnum_show(void)
{
SMG[0] = 22;
SMG[1] = 2 ;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = 16;
SMG[5] = read_num/100;
SMG[6] = read_num/10%10;
SMG[7] = read_num%10;
}
void writenum_show(void)
{
SMG[0] = 22;
SMG[1] = 1 ;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = 16;
SMG[5] = write_num/100;
SMG[6] = write_num/10%10;
SMG[7] = write_num%10;
}
void task()
{
if(show_mode==0){A1_show();}
else if(show_mode==1){A3_show();}
else if(show_mode==2){Voltage_show();}
else if(show_mode==3){writenum_show();}
else {readnum_show();}
}
void key_task()
{
task();
}
void key_work(void)
{
if(key_line)
{
P32=0;P33=1;P44=1;P42=1;
if(P44==0) //S5
{
while(!P44){key_task();}
if(++show_mode>4)show_mode=0;
}
if(P42==0) //S9
{
while(!P42){key_task();}
write_num++;
}
}
else
{
P32=1;P33=0;P44=1;P42=1;
if(P44==0) //S4
{
while(!P44){key_task();}
write_24c02(0x00,write_num);
}
if(P42==0) //S8
{
while(!P42){key_task();}
read_num=read_24c02(0x00);
}
}
}
void Timer1_Init(void)
{
AUXR |= 0x40; // 定时器时钟 1T 模式
TMOD &= 0x0F; // 设置定时器模式,仅修改 T1 的模式位
TL1 = 0x20; // 设置定时初始值
TH1 = 0xD1; // 设置定时初始值
TF1 = 0; // 清除 TF1 标志
TR1 = 1; // 定时器1开始计时
ET1 = 1; // 使能定时器1中断
}
int main(void)
{
read_num=read_24c02(0x00);
Timer1_Init(); // 初始化定时器1
EA = 1; // 开启全局中断
while(1)
{
key_work();
task();
}
}
// 定时器1中断服务函数
void Timer1_Isr(void) interrupt 3
{
if (++time_8ms == 8) // 每8次中断 (8ms) 更新一次数码管显示
{
time_8ms = 0; // 重置计数器
}
smg_enable_control(time_8ms, SMG[time_8ms]); // 动态显示,更新数码管
if(++time_15ms>15){time_15ms=0;key_line=~key_line;}
if(++time_200ms>=150){adc_chan1=adc(0x43),adc_chan3=adc(0x41);if(time_200ms>200){voltage=dac(51)*1.961,time_200ms=0;}}
}
5.温度读取部分
ds18b20温度读取:大约400ms读取一次 注意事项:在比赛中只给出onewire.c,需要自己添加onewire.h。同样的,并且底层驱动也不给出引脚定义,Delay部分也需要自己修改。ds18b20时序很严格,避免因为中断导致读取的出现问题,所以读取的时候关闭中断。上电第一次因为温度转换需要时间,所以延时一下,不然会显示85.00,因为默认就是85.00
实验现象:显示当前室内温度,保留两位小数
main.c
#include <STC15F2K60S2.H>
#include "onewire.h"
#include <intrins.h>
#define u8 unsigned char
#define u16 unsigned int
u8 timer_8ms;
u16 timer_400ms;
int temp;
u8 SMG[8];
u8 code t_display[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x00, 0x40, 0x76, 0x1E,
0x70, 0x38, 0x37, 0x5C, 0x73, 0x3E, 0x78, 0x3D, 0x67, 0x50,
0x37, 0x6E, 0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87,
0xFF, 0xEF, 0x46
};
// 位选控制代码,用于选择哪个数码管被点亮
u8 code T_COM[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void smg_enable_control(u8 wei, u8 duan)
{
P0 = 0xFF;
P2 = 0xC0;
P0 = T_COM[wei];
P2 = 0x00;
P2 = 0xE0;
P0 = ~t_display[duan];
P2 = 0x00;
}
//定时器1初始化函数
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
void temp_show(void)
{
SMG[0] = 16;
SMG[1] = 16;
SMG[2] = 16;
SMG[3] = 16;
SMG[4] = temp/1000;
SMG[5] = temp/100%10+32;
SMG[6] = temp/10%10;
SMG[7] = temp%10;
}
void Delay500ms(void) //@12.000MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 23;
j = 205;
k = 120;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
int main(void)
{
read_temp();//先读取一次数据
Delay500ms();//上电延时
Timer1_Init(); // 初始化定时器1
EA = 1; // 开启全局中断
while (1)
{
if(timer_400ms>400)
{
temp=read_temp()*100.0;
timer_400ms=0;
}
temp_show();
}
}
void Timer1_Isr(void) interrupt 3
{
if(++timer_8ms==8)
{
timer_8ms=0;
}
smg_enable_control(timer_8ms,SMG[timer_8ms]);
++timer_400ms;
}
onewire.c
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "onewire.h"
sbit DQ=P1^4;
//
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;i++);
}
}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
float read_temp(void)
{
unsigned char low,high;
unsigned int tem;
float temp;
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);
Delay_OneWire(200);
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE);
Delay_OneWire(200);
low=Read_DS18B20();
high=Read_DS18B20();
high&=0x0F;
tem=(high<<8)+low;
temp=tem*0.0625;
return temp;
}
onewire.h
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__
float read_temp(void);
#endif
6.ds1302
ds1302实时时钟:在1s内读取,推荐300ms 注意事项:在比赛中只给出ds1302.c,需要自己添加ds1302.h。引脚还是需要自己添加,一般情况下只需要用到时分秒 实验现象:9.00开始计时
main.c
#include <STC15F2K60S2.H>
#include "ds1302.h"
#define u8 unsigned char
#define u16 unsigned int
u8 timer_8ms,timer_200ms;
u8 SMG[8];
u8 code t_display[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x00, 0x40, 0x76, 0x1E,
0x70, 0x38, 0x37, 0x5C, 0x73, 0x3E, 0x78, 0x3D, 0x67, 0x50,
0x37, 0x6E, 0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87,
0xFF, 0xEF, 0x46
};
// 位选控制代码,用于选择哪个数码管被点亮
u8 code T_COM[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void smg_enable_control(u8 wei, u8 duan)
{
P0 = 0xFF;
P2 = 0xC0;
P0 = T_COM[wei];
P2 = 0x00;
P2 = 0xE0;
P0 = ~t_display[duan];
P2 = 0x00;
}
//定时器1初始化函数
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
void ds1302_show(void)
{
SMG[0] = DS1302_Time[3]/10;//F
SMG[1] = DS1302_Time[3]%10;//-
SMG[2] =17;
SMG[3] = DS1302_Time[4]/10;//高位熄灭
SMG[4] = DS1302_Time[4]%10;
SMG[5] = 17;
SMG[6] = DS1302_Time[5]/10;
SMG[7] = DS1302_Time[5]%10;
}
int main(void)
{
Init_DS1302();
Timer1_Init(); // 初始化定时器1
EA = 1; // 开启全局中断
while (1)
{
if(timer_200ms>200)
{
DS1302_ReadTime();
timer_200ms=0;
}
ds1302_show();
}
}
void Timer1_Isr(void) interrupt 3
{
if(++timer_8ms==8)
{
timer_8ms=0;
}
smg_enable_control(timer_8ms,SMG[timer_8ms]);
++timer_200ms;
}
ds1302.c
#include <STC15F2K60S2.H>
#include <intrins.h>
sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
//分别为年、月、日、时、分、秒、星期
unsigned char DS1302_Time[]={25,4,13,9,0,0,6};
//写入初始时间
void Init_DS1302()
{
RST=0;SCK=0; //复位
Write_Ds1302_Byte(0x8e,0x00);//写保护关
//十进制转BCD码后写入
//Write_Ds1302_Byte(0x8c,DS1302_Time[0]/10*16+DS1302_Time[0]%10); //年
//Write_Ds1302_Byte(0x88,DS1302_Time[1]/10*16+DS1302_Time[1]%10); //月
//Write_Ds1302_Byte(0x86,DS1302_Time[2]/10*16+DS1302_Time[2]%10); //日
Write_Ds1302_Byte(0x84,DS1302_Time[3]/10*16+DS1302_Time[3]%10); //时
Write_Ds1302_Byte(0x82,DS1302_Time[4]/10*16+DS1302_Time[4]%10); //分
Write_Ds1302_Byte(0x80,DS1302_Time[5]/10*16+DS1302_Time[5]%10); //秒
//Write_Ds1302_Byte(0x8a,DS1302_Time[6]/10*16+DS1302_Time[6]%10); //星期
Write_Ds1302_Byte(0x8e,0x80);
}
//读取后的时间存放于数组DS1302_Time[]
void DS1302_ReadTime()
{
//BCD码转十进制后读取
unsigned char Temp;
/*Temp=Read_Ds1302_Byte (0x8d);
DS1302_Time[0]=(Temp>>4)*10+Temp%16;
Temp=Read_Ds1302_Byte (0x8b);
DS1302_Time[6]=(Temp>>4)*10+Temp%16;
Temp=Read_Ds1302_Byte (0x89);
DS1302_Time[1]=(Temp>>4)*10+Temp%16;
Temp=Read_Ds1302_Byte (0x87);
DS1302_Time[2]=(Temp>>4)*10+Temp%16;*/
Temp=Read_Ds1302_Byte (0x85);//时
DS1302_Time[3]=(Temp>>4)*10+Temp%16;
Temp=Read_Ds1302_Byte (0x83);//分
DS1302_Time[4]=(Temp>>4)*10+Temp%16;
Temp=Read_Ds1302_Byte (0x81);//秒
DS1302_Time[5]=(Temp>>4)*10+Temp%16;
}
ds1302.h
#ifndef __DE1302_H
#define __DE1302_H
extern unsigned char DS1302_Time[];
void Init_DS1302();
void DS1302_ReadTime();
#endif
7.NE555频率计数
实验现象:显示测量的频率,注意要将P34与SIGNAL短接
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
u8 timer_8ms = 0;
u8 SMG[8];
// 定时器 0 初始化函数
u16 fre;//脉冲计数
u16 fre_count;//1s的脉冲数即频率
u16 timer_1s;//1000*1ms=1s
// 标准字符显示代码(共阴极数码管),这个不用记
u8 code t_display[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x00, 0x40, 0x76, 0x1E,
0x70, 0x38, 0x37, 0x5C, 0x73, 0x3E, 0x78, 0x3D, 0x67, 0x50,
0x37, 0x6E, 0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87,
0xFF, 0xEF, 0x46
};
// 位选控制代码,用于选择哪个数码管被点亮
u8 code T_COM[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void smg_enable_control(u8 wei, u8 duan)
{
P0 = 0xFF;
P2 = 0xC0;
P0 = T_COM[wei];
P2 = 0x00;
P2 = 0xE0;
P0 = ~t_display[duan];
P2 = 0x00;
}
void Timer0_Init(void)
{
TMOD = 0x07; //设置定时器模式
TL0 = 0xFF; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
}
//定时器1初始化函数
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
//频率显示函数
void freq_show(void)
{
SMG[0] = 15;//F
SMG[1] = 17;//-
SMG[2] = 16;
SMG[3] = (fre_count<10000)?16:fre_count/10000;//高位熄灭
SMG[4] = (fre_count<1000)?16:fre_count/1000%10;
SMG[5] = (fre_count<100)?16:fre_count/100%10;
SMG[6] = (fre_count<10)?16:fre_count/10%10;
SMG[7] = fre_count%10;
}
int main(void)
{
Timer1_Init(); // 初始化定时器1
Timer0_Init();
EA = 1; // 开启全局中断
while (1)
{
freq_show();
}
}
void Timer1_Isr(void) interrupt 3
{
if(++timer_8ms==8)
{
timer_8ms=0;
}
smg_enable_control(timer_8ms,SMG[timer_8ms]);/*详见数码管显示部分*/
if(++timer_1s==1000)
{
timer_1s=0;
fre_count=fre;
fre=0;
}
}
//定时器0中断服务函数
void Timer0_Isr() interrupt 1
{
++fre;//uint16_t类型
}
作者:JZYYYBB