飞行者 发表于 2025-8-29 22:00:59

15。定时器做计数器


tim.c
#include "tim.h"

u32 Count_T1 = 0;

//void TIM1_Count_Init(void)
//{
//        T1_CT = 1;                //设置外部计数
//        T1_M1 = 0;                //设置模式为16位自动重载
//        T1_M0 = 0;
//        T1_GATE = 0;
//       
//        TH1 = (65536-Count_num)>>8;         //65526
//        TL1 = (65536-Count_num);
//       
//        P3PU |= 0x20;

//       
//        TR1 = 1;
//        ET1 = 1;                //定时器/计数器T1的中断允许位
//}

//void Timer1_Isr(void) interrupt 3
//{
//        Count_T1++;                //T1引脚检测到10个脉冲就会溢出一次
//}

////定时器1计数
//void T1_RunTask(void)
//{
//        u32 count_th_tl = 0;
//        count_th_tl = ((u16)TH1<<8) + (u16)TL1;
//        count_th_tl -= 65526;
//       
//        SEG7_ShowLong(Count_T1 * Count_num + count_th_tl, 10);
//}

/*
任务2:编写INT1测量低电平时间
由按键模拟信号,100us的计数周期计数
*/
void Timer1_Isr(void) interrupt 3
{
        static u32 count_p33 = 0;        //p33计数变量初始值为0
       
        if(P33 == 0)                                //按键按下计数
        {
                count_p33 ++;
        }
        else
        {
                if(count_p33 > 0)
                {
                        Count_T1 = count_p33;
                }
                count_p33 = 0;
        }
       
}

void Timer1_Init(void)                //100微秒@24.000MHz
{
        AUXR &= 0xBF;                        //定时器时钟12T模式
        TMOD &= 0x0F;                        //设置定时器模式
        TL1 = 0x38;                                //设置定时初始值
        TH1 = 0xFF;                                //设置定时初始值
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
        ET1 = 1;                                //使能定时器1中断
}
//数码管输出Count_T1值
void T1_RunTask(void)
{
        //SEG7_ShowLong(Count_T1 , 10);        //整数输出
        SEG7_ShowString("%07.01f",((float)Count_T1)/10);
}


930931

飞行者 发表于 2025-8-29 22:04:54

15.定时器做计数器 课后小练

借鉴坛友乐高的课后作业
课后小练   
编译器一直有一个警告,消不掉。
CT计数器:
在设备的出料端口有一个感应器,每次有成品出来就会有一个低电平出来,计算相邻的两个产品出来的时间差来计算CT时间。
   1.计算P33引脚的相邻两次按下的时间,精确到100ms(即单个时间)
   2.计算按下P33的次数(即总产量)
3.数码管前四位显示单个时间 ,后四位显示次数

tim.c

#include "tim.h"
#include "io.h"


extern u32 Count_INT1;         // 从io.c外部引用,用于存储总产量计数
u32Count_T1 = 0;               // 定时器1计数值(每10ms加1)
u32Count1 = 0;               // 暂存的时间计数值
extern u32 Count;                // 从io.c外部引用,用于存储CT时间(100ms单位)

void INT1_Isr(void) interrupt 2
{

        Count1 = Count_T1;
        if(Count1 >5)
        {
                Count = Count1/10;
                Count_INT1++;
        }
        Count_T1 = 0;
       
       
}

void Ext_Init(void)
{
        IT1 = 1;                        //INT1(P3.3)下降沿中断
        EX1 = 1;                        //使能INT1中断
}


void Timer1_Isr(void) interrupt 3
{
        Count_T1++;
}

void Timer1_Init(void)                //100微秒@24.000MHz
{
        AUXR |= 0x40;                        //定时器时钟1T模式
        TMOD &= 0x0F;                        //设置定时器模式
        TL1 = 0xA0;                                //设置定时初始值
        TH1 = 0xF6;                                //设置定时初始值
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
        ET1 = 1;                                //使能定时器1中断
}
932


飞行者 发表于 2025-9-11 22:45:12

16 DS18b20测温

18b20.c
#include "18b20.h"

u8MinusFlag = 0;                //温度正负标志位,等于0为正数,等于1为负数
u32 Temp_18b20;                        //最终温度,放大了10000倍

void Delay480us(void)        //@24.000MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        _nop_();
        i = 2878UL;
        while (i) i--;
}
void Delay60us(void)        //@24.000MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        _nop_();
        i = 358UL;
        while (i) i--;
}
void Delay1us(void)        //@24.000MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        _nop_();
        i = 4UL;
        while (i) i--;
}

//复位(输出0保持480us,输出1保持60us,读取当前电平,延时420us)
void DS18B20_Reset(void)
{
        u8 flag = 1;
        while(flag)                //只要括号里的变量大于0,就会一直执行
        {
                DQ = 0;
                Delay480us();
                DQ = 1;
                Delay60us();
                flag = DQ;
                Delay480us();       
        }
}

//写逻辑0(输出0保持60us+,输出1保持1us+)
void DS18B20_Write_0(void)
{
        DQ = 0;
        Delay60us();
        DQ = 1;
        Delay1us();
        Delay1us();
}

//写逻辑1(输出0保持1us+,输出1保持60us+)
void DS18B20_Write_1(void)
{
        DQ = 0;
        Delay1us();
        Delay1us();
        DQ = 1;
        Delay60us();
}

//读逻辑0/1(输出0保持1us+,输出1保持1us+,读取当前电平,延时60us)
bit DS18B20_Read(void)
{
        bit state = 0;
        DQ = 0;
        Delay1us();
        Delay1us();
        DQ = 1;
        Delay1us();
        Delay1us();
        state = DQ;                //暂存这个DQ的值
        Delay60us();
       
        return state;        //读取单个位的数据
}


//写1字节(先输出低位,在输出高位)
void DS18B20_WriteByte( u8 dat )
{
        u8 i;
        for(i=0;i<8;i++)
        {
                if( dat & 0x01 )                //最低位是1,发逻辑1电平
                {
                        DS18B20_Write_1();
                }
                else                                        //否则,发逻辑0电平
                {
                        DS18B20_Write_0();
                }
                dat >>= 1;                                //dat = (dat>>1);
        }
}

//读1字节(先读到的是低位,后读到的是高位)
u8 DS18B20_ReadByte( void )
{
        u8 i;
        u8 dat=0;                                //数据暂存
        for(i=0;i<8;i++)                //循环读取八次
        {
                dat >>= 1;
                if( DS18B20_Read())
                {
                        dat |= 0x80;
                }
                else
                {
                }               
        }
        return dat;
}
//温度读取换算函数
//(复位-CCH-44H-等待-复位-CCH-BEH-读取2字节温度数据-换算)
void DS18B20_ReadTemp(void)
{
        u8TempH = 0;
        u8TempL = 0;
        u16 Temp = 0;
       
//-----------------发送检测命令--------------------------       
        DS18B20_Reset();                        //1,发送复位命令
        DS18B20_WriteByte(0xcc);        //2,跳过ROM命令
        DS18B20_WriteByte(0x44);        //3.开始转化命令
        while(!DQ);                                 //4.等待引脚变成高电平
       
//-----------------发送读取命令---------------------------
        DS18B20_Reset();                        //1,发送复位命令
        DS18B20_WriteByte(0xcc);                //2,跳过ROM命令
        DS18B20_WriteByte(0xBE);                //3.开始读取命令
        TempL = DS18B20_ReadByte(); //读取低字节温度
        TempH = DS18B20_ReadByte(); //读取高字节温度
       
        if( TempH & 0x80 )                        //如果最高位是1,这个就是负数
        {
                MinusFlag = 1;                        //标志位1,温度为负
                Temp = (((u16)TempH << 8) | ((u16)TempL << 0));                //两个八位转换为16位
                Temp = (~Temp)+1;                //负数补码,取反加1
                Temp_18b20 = (u32)Temp*625;        //最终温度       
        }
        else
        {
                MinusFlag = 0;                        //标志位1,温度为正
                Temp = (((u16)TempH << 8) | ((u16)TempL << 0));                //两个八位转换为16位
                Temp_18b20 = (u32)Temp*625;        //最终温度
        }
}940

飞行者 发表于 2025-9-11 22:56:34

16.DS18b20测温 课后小练 测温计 参考坛友“乐高”的16课课后小练代码


io.c
#include "io.h"
#include "18b20.h"

u8 Key_vol = 0;
u8MinusFlag;

u8 SEG_NUM[] =                                 //不带小数点
{
    0x3F,       /*'0', 0*/
    0x06,       /*'1', 1*/
    0x5B,       /*'2', 2*/
    0x4F,       /*'3', 3*/
    0x66,       /*'4', 4*/
    0x6D,       /*'5', 5*/
    0x7D,       /*'6', 6*/
    0x07,       /*'7', 7*/
    0x7F,       /*'8', 8*/
    0x6F,       /*'9', 9*/
    0x77,       /*'A', 10*/
    0x7C,       /*'B', 11*/
    0x39,       /*'C', 12*/
    0x5E,       /*'D', 13*/
    0x79,       /*'E', 14*/
    0x71,       /*'F', 15*/
    0x54,       /*'N', 16*/
    0x5C,       /*'O', 17*/
    0x73,       /*'P', 18*/
    0x50,       /*'R', 19*/
    0x40,       /*'-', 20*/
    0x00,       /*' ', 21*/
    0x80,       /*'.', 22*/
};
u8 SEG_NUM1[] =                                //带小数点
{
        0xBF,       /*'0', 0*/
    0x86,       /*'1', 1*/
    0xDB,       /*'2', 2*/
    0xCF,       /*'3', 3*/
    0xE6,       /*'4', 4*/
    0xED,       /*'5', 5*/
    0xFD,       /*'6', 6*/
    0x87,       /*'7', 7*/
    0xFF,       /*'8', 8*/
    0x6F,       /*'9', 9*/
    0x77,       /*'A', 10*/
    0x7C,       /*'B', 11*/
    0x39,       /*'9', 12*/
    0x5E,       /*'D', 13*/
    0x79,       /*'E', 14*/
    0x71,       /*'F', 15*/
    0x40,       /*'-', 16*/
    0x00,       /*' ', 17*/
    0x80,       /*'.', 18*/

};

u8 T_NUM =
{
        0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
};

void Init_595(void)
{
        HC595_SER= 0;
        HC595_RCK= 0;
        HC595_SCK= 0;
}


void Send_595( u8 dat )
{
        u8 i;
       
        for( i=0; i<8; i++ )
        {
                dat <<= 1;                        //数值左移一位
                HC595_SER= CY;        //数据写到引脚
          HC595_SCK= 1;                //输出上升沿的时钟信号
      HC595_SCK= 0;
        }
}


void Display_Seg( u8 HC595_1,u8 HC595_2)
{
        Send_595(HC595_1);                //数码管段码输出        高电平点亮
        Send_595(HC595_2);                //数码管位码输出        低电平点亮
       
        HC595_RCK= 1;                        //数据输出
        HC595_RCK= 0;
}


u8 passward = { 21,21,21,21,21,21,21,21};
u8 Seg_no = 0;
void SEG_Task0(void)                //未开机,熄屏
{

        switch(Seg_no)
                {
                case 0: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 1: Display_Seg( SEG_NUM, ~T_NUM );          break;
                case 2: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 3: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 4: Display_Seg( SEG_NUM, ~T_NUM );             break;
                case 5: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 6: Display_Seg( SEG_NUM1, ~T_NUM );          break;
                case 7: Display_Seg( SEG_NUM, ~T_NUM );          break;
                  }
               
               
}
void SEG_Task1(void)                ////开机2秒内显示"---C"
{

        switch(Seg_no)
                {
                case 0: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 1: Display_Seg( SEG_NUM, ~T_NUM );          break;
                case 2: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 3: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 4: Display_Seg( SEG_NUM, ~T_NUM );             break;
                case 5: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 6: Display_Seg( SEG_NUM, ~T_NUM );          break;
                case 7: Display_Seg( SEG_NUM, ~T_NUM );          break;
                  }
               
}
void SEG_Task2(void)                ////开机2秒内显示"---F"
{

        switch(Seg_no)
                {
                case 0: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 1: Display_Seg( SEG_NUM, ~T_NUM );          break;
                case 2: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 3: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 4: Display_Seg( SEG_NUM, ~T_NUM );             break;
                case 5: Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 6: Display_Seg( SEG_NUM, ~T_NUM );          break;
                case 7: Display_Seg( SEG_NUM, ~T_NUM );          break;
                  }
               
}
void SEG_Task3(void)                //开机2秒后正常显示摄氏温度
{

        switch(Seg_no)
                {
                case 0: Display_Seg( SEG_NUM], ~T_NUM );                   break;
                case 1: Display_Seg( SEG_NUM], ~T_NUM );         break;
                case 2: Display_Seg( SEG_NUM], ~T_NUM );                   break;
                case 3: if(MinusFlag)
                                Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 4: Display_Seg( SEG_NUM], ~T_NUM );             break;
                case 5: Display_Seg( SEG_NUM1], ~T_NUM );                   break;
                case 6: Display_Seg( SEG_NUM], ~T_NUM );         break;
                case 7: Display_Seg( SEG_NUM, ~T_NUM );         break;
               
                  }
               
}
void SEG_Task4(void)                //开机2秒后正常显示华氏温度
{

        switch(Seg_no)
                {
                case 0: Display_Seg( SEG_NUM], ~T_NUM );                   break;
                case 1: Display_Seg( SEG_NUM], ~T_NUM );         break;
                case 2: Display_Seg( SEG_NUM], ~T_NUM );                   break;
                case 3: if(MinusFlag)
                                Display_Seg( SEG_NUM, ~T_NUM );                   break;
                case 4: Display_Seg( SEG_NUM], ~T_NUM );             break;
                case 5: Display_Seg( SEG_NUM1], ~T_NUM );                   break;
                case 6: Display_Seg( SEG_NUM], ~T_NUM );         break;
                case 7: Display_Seg( SEG_NUM, ~T_NUM );         break;
                  }
               
}

u16 Timing = 0;                        //计时
bit Temp_C_F;                        //温度标志位,1(真)华氏,0(假)摄氏
bit run = 0;                        //开关机标志位,0关机,1开机

void SEG_Show(void)
{
        u8 num =0;
        if(run == 0)                //没有按下开机键
        {
                Timing = 0;
                SEG_Task0();        //执行息屏函数
        }
        else
        {
                Timing++;
                if(Timing>2000)
                {
                        if(Temp_C_F)
                                SEG_Task4();
                        else
                                SEG_Task3();
                        Timing = 2000;
                }
                else
                {
                       if(Temp_C_F)
                               SEG_Task2();
                       else
                               SEG_Task1();
                }
        }
        Seg_no ++;
        if( Seg_no>7 )
                Seg_no=0;
}

void SEG_Show_U32(u32 num)
{
        u8 i;
        for(i=0; i<3;i++)
        {
                passward = num%10;
                num /= 10;
        }
}
//u8 Key_Vol3 = 0;                                                //判断按钮是否按下
u8 Key_no = 0;                                                        //数码管位计数
u16 key_num;

void KEY_Task(void)
{
//---------------开关机-------------------------
                if(Temp_C_F == 0)
                        SEG_Show_U32(Temp_18b20);
                else
                        SEG_Show_U32(Temp_F);
                if(P01 == 0)
                {
                       
                        if(P01 == 0)
                        {
                                run = !run;
                                key_num = 0;
                        }
                        while(P01 == 0);
                }
//---------------华氏摄氏转换-------------------------       
        key_num++;
        if(P03 == 0)
        {
                Key_vol++;
                key_num = 0;
                if(Key_vol == 5)
                {
                        Temp_C_F = !Temp_C_F;
                }
        }
        else
                Key_vol = 0;
        if(key_num == 3000)
                run = 0;
               
}



941

飞行者 发表于 2025-9-14 21:28:09

17.串口的简单应用


usart.c
#include "usart.h"
#include "io.h"

u8 Rec_Dat;                //接收缓冲区
u8 Rec_Num = 0;                //接收计数
bit B_TX2_Busy = 0;        //发送完成标志位

void Uart2_Isr(void) interrupt 8
{
        if (S2CON & 0x02)        //检测串口2发送中断
        {
                S2CON &= ~0x02;        //清除串口2发送中断请求位
                B_TX2_Busy = 0;        //发送完成清零
        }
        if (S2CON & 0x01)        //检测串口2接收中断
        {
                S2CON &= ~0x01;        //清除串口2接收中断请求位
               
                Rec_Dat = S2BUF;
        }
}

void Uart2_Init(void)        //9600bps@24.000MHz
{
       
        P_SW2 |= 0x01;                //UART2/USART2: RxD2(P4.2), TxD2(P4.3)

       
        S2CON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x04;                //定时器时钟1T模式
        T2L = 0x8F;                        //设置定时初始值
        T2H = 0xFD;                        //设置定时初始值
        AUXR |= 0x10;                //定时器2开始计时
        IE2 |= 0x01;                //使能串口2中断
       
        B_TX2_Busy = 0;
        Rec_Num = 0;       
}

void Uart2_SendStr(u8 *puts)                        //串口数据发送函数
{
           for (; *puts != 0;puts++)   //遇到停止符0结束
    {
      S2BUF = *puts;
      B_TX2_Busy = 1;
      while(B_TX2_Busy);
    }
}

/*
1.发送OPEN\r\n打开数码管,数码管显示“- - - -”
思路:判断发送的数据最后六位,是否等于open\r\n,只要检测到OPEN\r\n ,
OPEN前面的数据都可以忽略不计
2.发送CLOSE\r\n打开数码管,数码管全部熄灭
*/

void Usart2_RunTask(void)
{
        if(Rec_Num >= 6)        //是否接收到了6位以上的数据
        {
                if((Rec_Dat == '\n') && (Rec_Dat == '\r'))                //数据末尾判断
                {
                        if((Rec_Dat == 'O') && (Rec_Dat == 'P') && (Rec_Dat == 'E') && (Rec_Dat == 'N'))
                        {
                                passward = 20;
                                passward = 20;
                                passward = 20;
                                passward = 20;
                                Uart2_SendStr("打开成功\r\n");
                        }
                        else if((Rec_Dat == 'C') && (Rec_Dat == 'L') && (Rec_Dat == 'O') && (Rec_Dat == 'S') && (Rec_Dat == 'E'))
                        {
                                passward = 21;
                                passward = 21;
                                passward = 21;
                                passward = 21;
                                Uart2_SendStr("关闭成功\r\n");
                        }
                        Rec_Num = 0;
                }
               
        }
}943

飞行者 发表于 2025-9-14 21:31:37

17.串口的简单应用课后小练 智能数码管显示屏


void Usart2_RunTask(void)
void Usart2_RunTask(void)
{
      if(Rec_Num >= 6)      //是否接收到了6位以上的数据
      {
                if((Rec_Dat == '\n') && (Rec_Dat == '\r'))                //数据末尾判断
                {
                        if((Rec_Dat == 'O') && (Rec_Dat == 'P') && (Rec_Dat == 'E') && (Rec_Dat == 'N'))
                        {
                              passward = 20;
                              passward = 20;
                              passward = 20;
                              passward = 20;
                              Uart2_SendStr("打开成功\r\n");
                        }
                        else if((Rec_Dat == 'C') && (Rec_Dat == 'L') && (Rec_Dat == 'O') && (Rec_Dat == 'S') && (Rec_Dat == 'E'))
                        {
                              passward = 21;
                              passward = 21;
                              passward = 21;
                              passward = 21;
                              Uart2_SendStr("关闭成功\r\n");
                        }else if((Rec_Dat == 'D') &&(Rec_Dat == 'A') &&(Rec_Dat == 'T') && (Rec_Dat == '+') && (Rec_Dat == '1') && (Rec_Dat == '2') && (Rec_Dat == '3'))
                        {
                              passward = 1;
                              passward = 2;
                              passward = 3;
//                              passward = 21;
                              Uart2_SendStr("发送成功\r\n");
                        }
                        Rec_Num = 0;
                }
               
      }
}944


页: 1 2 3 [4]
查看完整版本: Ai8051u擎天柱学习冲哥《8051U深度入门到32位51大型实战视频》记录贴