蓝桥杯单片全模块模板详解

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

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯单片全模块模板详解

发表回复