小蜜蜂笔记
嵌入式开发与物联网应用教育践行者

【STM8教程-09】STM8基础技能的综合应用

项目案例:自动照明系统控制与运行监测

硬件资源:LED指示灯,定时器TIM4,ADC的第12通道,串行接口。
D3灯 <——– PC1。
D4灯 <——– PC2。
D5灯 <——– PC3。
D6灯 <——– PC4。
光敏电阻 ——–> PF4/ADC12。
串行接口UART2。
硬件电路相关信息,详见:XMF06A开发的电路结构框图

功能要求:
1.  系统的主时钟采用默认的高速内部振荡器8分频,即2MHz
2. 串行接口UART2的波特率为9600BSP,1位起始位,8位数据位,1位停止位。
3. 串口的数据发送采用查询方式,串口数据的接收采用中断方式
4. 初始化ADC模数转换器,对12通道进行单次转换,采样结果数据左对齐,其他参数配置保持默认。
5. 利用8位基本型定时器TIM4实现2ms的间隔定时,并通过累计定时中断次数的方法实现1秒钟的间隔定时,每隔1秒钟切换D3灯的开关状态,实现一个秒闪指示灯。
6. 自定时器启动后,以秒为单位累计系统的运行时间
7. 每隔2ms对ADC的12通道进行单次转换,采样光敏电阻的电压数据,并对采样值进行判断,当采样数值小于最大值的一半时,自动点亮D6灯,打开自动照明系统,反之,自动熄灭D6灯,关闭D6灯。
8. 系统上电开机后, 首先先上位机发送一个欢迎信息,具体内容如下图所示。然后以跑马灯的方式巡检4个LED灯的工作状态。
9. 在主函数中,循环查询上位机控制命令字。当收到0xA3的命令字后,向上位机发送系统当前的运行信息,包括:系统运行时间光照的电压值自动照明系统的工作状态。具体内容参照下图。

案例的源码及注释

#include "iostm8s105k6.h"
#include "stdio.h"

#define D3      PC_ODR_ODR1
#define D4      PC_ODR_ODR2
#define D5      PC_ODR_ODR3
#define D6      PC_ODR_ODR4

unsigned char Recv_dat = 0;     //接收上位机的命令字
unsigned int dat_ADC12, = 0;    //ADC采样的原始数据
unsigned int dat_Volt = 0;      //换算的电压值
unsigned int count = 0,;        //间隔定时中断次数累计
unsigned int t_run = 0;         //系统运行时间累计
unsigned char F_2ms = 0;        //2ms间隔定时标志

/*=========================普通延时函数==========================*/
void Delay(unsigned int t)
{
  while(t--);
}
/*=========================灯光测试函数==========================*/
void LED_Check()
{
  //D3灯到D6灯依次点亮
  D3 = 1;               //D3灯点亮
  Delay(60000);
  D4 = 1;               //D4灯点亮
  Delay(60000);
  D5 = 1;               //D5灯点亮
  Delay(60000);
  D6 = 1;               //D6灯点亮
  Delay(60000);
  //D3灯到D6灯依次熄灭
  D3 = 0;               //D3灯熄灭
  Delay(60000);
  D4 = 0;               //D4灯熄灭
  Delay(60000);
  D5 = 0;               //D5灯熄灭
  Delay(60000);
  D6 = 0;               //D6灯熄灭
  Delay(60000);
}
/*========================GPIO端口初始化=========================*/
void Init_GPIO()
{
  //初始化D3灯、D4灯、D5灯、D6灯的引脚
  PC_DDR |= 0x1e;       //PC1、PC2、PC3、PC4设置为输出模式
  PC_CR1|= 0x1e;        //PC1、PC2、PC3、PC4设置为推挽输出
  PC_CR2&= ~0x1e;       //PC1、PC2、PC3、PC4输出速度最大为2MHz
}
/*=======================TIM4定时器初始化========================*/
void Init_TIM4()
{
  asm("rim");           //打开总中断
  TIM4_CR1=0x00;        //关闭计数器
  TIM4_IER=0x01;        //更新中断使能
  TIM4_EGR=0x01;        //
  
  TIM4_PSCR=0x04;       //2MHz的主时钟16分频为125KHz
  TIM4_CNTR=250;        //最大计数值250,间隔定时为2ms
  TIM4_ARR=250;         //自动重装的值
  
  TIM4_CR1=0x01;        //使能计数器
  asm("rim");           //打开总中断
}
/*==================TIM4定时溢出中断服务函数=====================*/
#pragma vector = TIM4_OVR_UIF_vector    
__interrupt void TIM4_OVR_UIF_IRQHandler()
{
  count++;
  F_2ms = 1;            //标志间隔定时2ms时间到了
  TIM4_SR = 0x00;
  if(count == 500)      //2ms * 500 = 1000ms = 1s
  {
    count = 0;          //间隔定时中断次数累计清零
    t_run++;            //系统运行时间秒数累计
    D3 = ~D3;           //秒闪指示灯控制
  }
}
/*=======================串口UART2初始化=========================*/
void Init_UART2()
{
  asm("rim");                   //打开总中断
  //在默认的2MHz时钟源下,波特率:9600
  //UART_DIV = 2000000/9600 = 208 = 0x0d00
  UART2_BRR2 = 0x00;            //先写BRR2 
  UART2_BRR1 = 0x0d;            //再写BRR1
  UART2_CR2 = 0x2c;             //允许接收和发送,使能接收中断 
  asm("rim");                   //打开总中断
}

/*=====================串口发送单字节函数========================*/
void UR2_Send_Byte(unsigned char dat)
{
  while((UART2_SR & 0x80)==0x00);  
  UART2_DR = dat;               //发送一个字节
}
/*======================串口发送字符串函数=======================*/
void UR2_Send_String(unsigned char *str )
{
  while(*str != '\0')           //发送一个字符串
  {
    UR2_Send_Byte(*str++);      //逐个发送字符串中的字节
  }
}
/*====================UART2接收中断服务函数======================*/
#pragma vector= UART2_R_OR_vector
__interrupt void UART2_R_OR_IRQHandler()  
{
  Recv_dat = UART2_DR;          //将接收到的数据读取出来
}
/*======================ADC12初始化函数==========================*/
void Init_ADC12()
{
  ADC_CSR_CH = 12;              //选择通道AIN12
  ADC_CR1_ADON = 1;             //首次将ADON位置1,唤醒
}
/*=================ADC数据采样与换算函数=========================*/
void Read_ADC12()
{
  ADC_CR1_ADON = 1;             //启动ADC转换
  while(ADC_CSR_EOC == 0);      //等待转换完成
  ADC_CSR_EOC = 0;              //清除转换完成标志
  
  dat_ADC12 = ADC_DRH;          //数据左对齐
  dat_ADC12 = (dat_ADC12 << 2) | ADC_DRL;
  
  if(dat_ADC12 < 512)           //如果光照电压小于最大值的一半
  {
    D6 = 1;                     //打开自动照明系统
  }
  else                          //否则
  {
    D6 = 0;                     //关闭照明系统
  }
}
/*=====================系统运行信息上传函数=======================*/
void Send_Sys_Info()
{
  unsigned char buf[32];        //字符串格式化缓存
  dat_Volt = dat_ADC12 * 32 / 10;
  
  UR2_Send_String("=================================\r\n");
  sprintf(buf, "系统运行时间: %d秒\r\n",t_run);
  UR2_Send_String(buf); 
  sprintf(buf, "光照的电压值: %dmV\r\n",dat_Volt);
  UR2_Send_String(buf);
  if(D6 == 1)
  {
    sprintf(buf, "自动照明系统: 打开\r\n");
  }
  else
  {
    sprintf(buf, "自动照明系统: 关闭\r\n");
  }
  UR2_Send_String(buf);
  UR2_Send_String("=================================\r\n");
}
/*===========================主函数==============================*/
void main()
{
  Init_GPIO();                  //初始化GPIO
  Init_UART2();                 //初始化UART2
  Init_ADC12();                 //初始化ADC
  Init_TIM4();                  //初始化TIM4
  
  UR2_Send_String("****************************************\r\n");
  UR2_Send_String("   小蜜蜂笔记网 www.xmf393.com 欢迎您!\r\n");
  UR2_Send_String("****************************************\r\n");
  LED_Check();                  //跑马灯检测
  
  while(1)
  {
    if(F_2ms == 1)              //2ms间隔定时检测
    {
      Read_ADC12();             //更新光照传感器数据并控制照明系统
       F_2ms = 0;               //清除间隔定时标志
    }
    if(Recv_dat == 0xa3)        //如果接收到的数据为0xa3命令字
    {
      Send_Sys_Info();          //上传系统运行状态      
      Recv_dat = 0;             //清除命令字变量
    }
  }
}

赞(2)
未经允许不得转载:小蜜蜂笔记 » 【STM8教程-09】STM8基础技能的综合应用

小蜜蜂笔记 更专业 更方便 更高效

联系我们精品小店