基于RT-Thread的环境监测装置(含IO口模拟8080时序驱动TFT屏幕)

                        基于RT-Thread的环境监测装置

一、活动介绍

      ART-Pi 是 RT-Thread 团队经过半年的精心准备,专门为嵌入式软件工程师、开源创客设计的一款极具扩展功能的 DIY 开源硬件。
在这里插入图片描述
ART-Pi 官方网站
官方网站:ART-Pi (gitee.io)

ART-Pi SDK 仓库
GitHub主仓库:RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi (github.com)

板载资源:
  • STM32H750XBH6
  • On-board ST-LINK/V2.1
  • USB OTG with Type-C connector
  • SDIO TF Card slot
  • SDIO WIFI:AP6212
  • HDC UART BuleTooth:AP6212
  • RGB888 FPC connector
  • 32-Mbytes SDRAM
  • 16-Mbytes SPI FLASH
  • 8-Mbytes QSPI FLASH
  • D1(blue) for 3.3 v power-on
  • Two user LEDs:D2 (blue),D2 (red)
  • Two ST-LINK LEDs: D4(blue),D4 (red)
  • Two push-buttons (user and reset)
扩展接口:
  • 4路UART(LPUART)
  • 3路SPI
  • 2路hardware iic
  • 1路USB-FS
  • 1路ETH
  • 1路SAI
  • 1路DCMI
  • 2路CANFD
  • 超过5路ADC (支持查分输入ADC)
  • 超过15路PWM(支持高精度定时器HRTIM)
驱动支持:
  • UART
  • SPI
  • SDMMC
  • CAN
  • QSPI
  • ADC
  • PWM
  • DCMI
  • SAI
  • LTDC
  • USB
  • ETH
  • SDRAM
  • HRTIM
  • I2C
    在这里插入图片描述
          作为一款仰慕已久的开发板,ART-Pi可以作为学习RT-Thread的必备良品,根据立创的活动,需要基于ART-Pi设计一款开发板。正好手头有闲置的TFT屏幕,ART-Pi上具备RGB接口,但是我想基于IO口模拟8080时序做一个屏幕驱动,所以便在立创商城购买了2.8寸的TFT屏幕。不得不说,蓝色的屏幕看久了,这黑色PCB的屏幕是格外的好看,加上黑色的PCB板,B格满满。

二、设备介绍

      首先以驱动TFT屏幕为目的,那么加上温度传感器和MQ2气体传感器还有光敏电阻做一个环境监测吧,这种就比较适合于车内监测,MQ2气体传感器可以监测多种有害气体。
实物图来了
      实物如上图所示,PCB没有做的过分大,基于ART-Pi的底板进行设计,排针都是Pin to Pin连接,因为屏幕需要在上面安装,但是光敏电阻和MQ2气体检测模块必须外置。这里只能选择将半个屏幕放在外面,等会上图看效果,放在外面也挺好看,还是上面说的B格满满O(∩_∩)O哈哈~。

2.1主要功能

      目前使用非16个连续IO口模拟8080时序,通过8080协议驱动2.8寸TFT屏幕, 这个驱动移植真的费劲,网上的资料都是连续的16个引脚,直接按位操作即可,这里将资料开放出来,供大家以后参考。
目前实现的功能有,DHT11的温湿度监测,MQ2气体检测模块的有害气体检测和光敏电阻的光照监测。

三、硬件介绍

      硬件部分其实挺简单的,当然主角就是我们的Art-Pi啦,随机选取16个IO口作为显示屏的8080协议引脚,当时没有具体去查ART-Pi的手册将35 37 麦克风引脚接入,所以目前是与其他外设公用这两个引脚,但是我没有使能其他外设,所以没有影响。以后画板子之前一定要把引脚了解清楚再去设计。

在这里插入图片描述
      除了8080总线之外,板子还有三个LED灯,作为报警灯和正常工作状态的灯,不得不说这紫罗兰颜色的贴片LED是真的好看,以前都是什么红色绿色,这次接触了这种比较骚的颜色,以后给小姐姐送礼物的时候有得搞头了O(∩_∩)O哈哈~。
在这里插入图片描述
      显示屏的接口在这里,简单粗暴,虽然这些IO口不支持FMC,但是为了方便去标记,还是使用了FMC的网络标号,这样也方便后面写8080协议去控制。
在这里插入图片描述
      为了便于引脚分配,之后特意查看了ART-Pi的原理图,将所有8080协议的IO口全部标识出来,方便在RT-Thread上移植。
在这里插入图片描述
      这里是大三传感器模块,

      1. DHT11是一款有已校准数字信号输出的温湿度传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度5-95%RH, 温度0~+50℃。DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。
      2. MQ-2气体传感器所使用的气敏材料是在清洁空气中电导率较低的二氧化锡(SnO2)。当传感器所处环境中存在可燃气体时,传感器的电导率随空气中可燃气体浓度的增加而增大。使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。MQ-2气体传感器可用于家庭和工厂的气体泄漏检测,适宜对液化气、丁烷、丙烷、甲烷、酒精、氢气、烟雾等的探测,对天然气和其它可燃蒸汽的检测也很理想。这种传感器可检测多种可燃性气体,是一款适合多种应用的低成本传感器。
      3.光敏电阻是用硫化镉或硒化镉等半导体材料制成的特殊电阻器,其工作原理是基于内光电效应。光照愈强,阻值就愈低,随着光照强度的升高,电阻值迅速降低,亮电阻值可小至1KΩ以下。光敏电阻对光线十分敏感,其在无光照时,呈高阻状态,暗电阻一般可达1.5MΩ。光敏电阻的特殊性能,随着科技的发展将得到极其广泛应用。

在这里插入图片描述
       这里使用这三种传感器作为主要的监测设备。

四、软件分享

首先我在ART-Pi中移植了8080协议总线,因为使用的分散的IO口,所以无法使用按位操作,只能使用IO口进行操作。

1.首先是初始化需要使用的GPIO
void ILI9341_GPIO_Config ()
{
                    /*初始化LCD的控制线*/

        rt_pin_mode(ILI9341_RD_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_WR_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_CS_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_DC_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_BK_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_RST_CLK,PIN_MODE_OUTPUT);


                    /*初始化LCD的数据线*/

        rt_pin_mode(ILI9341_D0_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D1_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D2_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D3_CLK,PIN_MODE_OUTPUT);

        rt_pin_mode(ILI9341_D4_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D5_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D6_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D7_CLK,PIN_MODE_OUTPUT);

        rt_pin_mode(ILI9341_D8_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D9_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D10_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D11_CLK,PIN_MODE_OUTPUT);

        rt_pin_mode(ILI9341_D12_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D13_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D14_CLK,PIN_MODE_OUTPUT);
        rt_pin_mode(ILI9341_D15_CLK,PIN_MODE_OUTPUT);


}
2.其实,在8080总线中,需要有读过程,也需要有写过程,所以需要设定IO口的输出与输出模式。这里已经将IO口定义好,数据处理如下所示,DATAOUT输入的变量即为需要发送的数据,直接通过按位与和位移动的方式进行逐个IO口处理,将数据发送出去。
void DATAOUT(unsigned int x)
{

    rt_pin_write(ILI9341_D0_CLK,(x>>0&0x0001));
    rt_pin_write(ILI9341_D1_CLK,(x>>1&0x0001));
    rt_pin_write(ILI9341_D2_CLK,(x>>2&0x0001));
    rt_pin_write(ILI9341_D3_CLK,(x>>3&0x0001));

    rt_pin_write(ILI9341_D4_CLK,(x>>4&0x0001));
    rt_pin_write(ILI9341_D5_CLK,(x>>5&0x0001));
    rt_pin_write(ILI9341_D6_CLK,(x>>6&0x0001));
    rt_pin_write(ILI9341_D7_CLK,(x>>7&0x0001));

    rt_pin_write(ILI9341_D8_CLK,(x>>8&0x0001));
    rt_pin_write(ILI9341_D9_CLK,(x>>9&0x0001));
    rt_pin_write(ILI9341_D10_CLK,(x>>10&0x0001));
    rt_pin_write(ILI9341_D11_CLK,(x>>11&0x0001));

    rt_pin_write(ILI9341_D12_CLK,(x>>12&0x0001));
    rt_pin_write(ILI9341_D13_CLK,(x>>13&0x0001));
    rt_pin_write(ILI9341_D14_CLK,(x>>14&0x0001));
    rt_pin_write(ILI9341_D15_CLK,(x>>15&0x0001));

}
3.输入模式如下:
uint16_t DATAIN(void)
{
    volatile uint16_t data = 0;

    data |= pin_read(ILI9341_D15_CLK);data <<= 1;
    data |= pin_read(ILI9341_D14_CLK);data <<= 1;
    data |= pin_read(ILI9341_D13_CLK);data <<= 1;
    data |= pin_read(ILI9341_D12_CLK);data <<= 1;
    data |= pin_read(ILI9341_D11_CLK);data <<= 1;
    data |= pin_read(ILI9341_D10_CLK);data <<= 1;
    data |= pin_read(ILI9341_D9_CLK);data <<= 1;
    data |= pin_read(ILI9341_D8_CLK);data <<= 1;
    data |= pin_read(ILI9341_D7_CLK);data <<= 1;
    data |= pin_read(ILI9341_D6_CLK);data <<= 1;
    data |= pin_read(ILI9341_D5_CLK);data <<= 1;
    data |= pin_read(ILI9341_D4_CLK);data <<= 1;
    data |= pin_read(ILI9341_D3_CLK);data <<= 1;
    data |= pin_read(ILI9341_D2_CLK);data <<= 1;
    data |= pin_read(ILI9341_D1_CLK);data <<= 1;
    data |= pin_read(ILI9341_D0_CLK);

    return data;
}
char  pin_read(rt_base_t     pin)
{
    if(rt_pin_read(pin)==0)
    {
        return 0;
    }

    else
        return 1;
}
4.写数据,写数据函数没有什么难度,除了控制几个信号位的IO口外,直接使用上面写的发送数据函数进行数据发送即可。
//写数据函数
//可以替代LCD_WR_DATAX宏,拿时间换空间.
//data:寄存器值
void LCD_WR_DATAX(uint16_t data)
{
    rt_pin_write(ILI9341_DC_CLK, PIN_HIGH);//开始片选
        //LCD_RS_SET;
    rt_pin_write(ILI9341_CS_CLK, PIN_LOW);//开始片选
        //LCD_CS_CLR;
    DATAOUT(data);//输出数据
        //DATAOUT(data);
    rt_pin_write(ILI9341_WR_CLK, PIN_LOW);//写入开始
        //LCD_WR_CLR;
    rt_pin_write(ILI9341_WR_CLK, PIN_HIGH);//写入结束
        //LCD_WR_SET;
    rt_pin_write(ILI9341_CS_CLK, PIN_HIGH);//结束片选
        //LCD_CS_SET;
}
5.读数据,读数据函数是十分麻烦的,在这里需要将所有IO口设置为输入模式,而且由于不是连续的IO口,无法直接读 例如PA寄存器的值,所以这里只能写一个协议,逐个读取IO口然后通过上面的DATAIN函数将各位 拼为一个16位的二进制数字,转为16进制进行判断。
//读LCD数据
//返回值:读到的值
uint16_t LCD_RD_DATA(void)
{
    uint16_t t;
    //设置为上拉输入模式
    rt_pin_mode(ILI9341_D0_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D1_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D2_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D3_CLK,PIN_MODE_INPUT_PULLUP);

    rt_pin_mode(ILI9341_D4_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D5_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D6_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D7_CLK,PIN_MODE_INPUT_PULLUP);

    rt_pin_mode(ILI9341_D8_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D9_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D10_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D11_CLK,PIN_MODE_INPUT_PULLUP);

    rt_pin_mode(ILI9341_D12_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D13_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D14_CLK,PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(ILI9341_D15_CLK,PIN_MODE_INPUT_PULLUP);

    DATAOUT(0X0000);

    rt_pin_write(ILI9341_DC_CLK, PIN_HIGH);
        //LCD_RS_SET;
    rt_pin_write(ILI9341_CS_CLK, PIN_LOW);
        //LCD_CS_CLR;
    rt_pin_write(ILI9341_RD_CLK, PIN_LOW);
    //读取数据(读寄存器时,并不需要读2次)
    //LCD_RD_CLR;

    if(lcddev.id==0X8989)
    {
        delay_us(20);//FOR 8989,延时2us
    }
    t=DATAIN();

    rt_pin_write(ILI9341_RD_CLK, PIN_HIGH);
        //LCD_RD_SET;
    rt_pin_write(ILI9341_CS_CLK, PIN_HIGH);
        //LCD_CS_SET;

    //设置为推挽输出模式
    rt_pin_mode(ILI9341_D0_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D1_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D2_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D3_CLK,PIN_MODE_OUTPUT);

    rt_pin_mode(ILI9341_D4_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D5_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D6_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D7_CLK,PIN_MODE_OUTPUT);

    rt_pin_mode(ILI9341_D8_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D9_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D10_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D11_CLK,PIN_MODE_OUTPUT);

    rt_pin_mode(ILI9341_D12_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D13_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D14_CLK,PIN_MODE_OUTPUT);
    rt_pin_mode(ILI9341_D15_CLK,PIN_MODE_OUTPUT);

    DATAOUT(0XFFFF);

    return t;
}
6.因为我使用的TFT 驱动芯片是ILI9341,所以这里对于9341做了特定修改,完成屏幕初始化操作。
void  LCD_Init()
{
    ILI9341_GPIO_Config();

    rt_pin_write(ILI9341_RST_CLK, PIN_HIGH);
    rt_pin_write(ILI9341_RST_CLK, PIN_LOW);
    rt_pin_write(ILI9341_RST_CLK, PIN_HIGH);

    rt_thread_mdelay(50);

    LCD_WriteReg(0x0000,0x0001);
    rt_thread_mdelay(50);
    lcddev.id = LCD_ReadReg(0x0000);
    printf(" LCD ID:%x\r\n",lcddev.id); //打印LCD ID
    if(lcddev.id==0x9325)//9325
    {
        LCD_WriteReg(0x00E5,0x78F0);
        LCD_WriteReg(0x0001,0x0100);
        LCD_WriteReg(0x0002,0x0700);
        LCD_WriteReg(0x0003,0x1030);
        LCD_WriteReg(0x0004,0x0000);
        LCD_WriteReg(0x0008,0x0202);
        LCD_WriteReg(0x0009,0x0000);
        LCD_WriteReg(0x000A,0x0000);
        LCD_WriteReg(0x000C,0x0000);
        LCD_WriteReg(0x000D,0x0000);
        LCD_WriteReg(0x000F,0x0000);
        //power on sequence VGHVGL
        LCD_WriteReg(0x0010,0x0000);
        LCD_WriteReg(0x0011,0x0007);
        LCD_WriteReg(0x0012,0x0000);
        LCD_WriteReg(0x0013,0x0000);
        LCD_WriteReg(0x0007,0x0000);
        //vgh
        LCD_WriteReg(0x0010,0x1690);
        LCD_WriteReg(0x0011,0x0227);
        rt_thread_mdelay(10);
        //vregiout
        LCD_WriteReg(0x0012,0x009D); //0x001b
        rt_thread_mdelay(10);
        //vom amplitude
        LCD_WriteReg(0x0013,0x1900);
        rt_thread_mdelay(10);
        //vom H
        LCD_WriteReg(0x0029,0x0025);
        LCD_WriteReg(0x002B,0x000D);
        //gamma
        LCD_WriteReg(0x0030,0x0007);
        LCD_WriteReg(0x0031,0x0303);
        LCD_WriteReg(0x0032,0x0003);// 0006
        LCD_WriteReg(0x0035,0x0206);
        LCD_WriteReg(0x0036,0x0008);
        LCD_WriteReg(0x0037,0x0406);
        LCD_WriteReg(0x0038,0x0304);//0200
        LCD_WriteReg(0x0039,0x0007);
        LCD_WriteReg(0x003C,0x0602);// 0504
        LCD_WriteReg(0x003D,0x0008);
        //ram
        LCD_WriteReg(0x0050,0x0000);
        LCD_WriteReg(0x0051,0x00EF);
        LCD_WriteReg(0x0052,0x0000);
        LCD_WriteReg(0x0053,0x013F);
        LCD_WriteReg(0x0060,0xA700);
        LCD_WriteReg(0x0061,0x0001);
        LCD_WriteReg(0x006A,0x0000);
        //
        LCD_WriteReg(0x0080,0x0000);
        LCD_WriteReg(0x0081,0x0000);
        LCD_WriteReg(0x0082,0x0000);
        LCD_WriteReg(0x0083,0x0000);
        LCD_WriteReg(0x0084,0x0000);
        LCD_WriteReg(0x0085,0x0000);
        //
        LCD_WriteReg(0x0090,0x0010);
        LCD_WriteReg(0x0092,0x0600);

        LCD_WriteReg(0x0007,0x0133);
        LCD_WriteReg(0x00,0x0022);//
    }
    LCD_Display_Dir(0);         //默认为竖屏
    LCD_DisplayOn();
    rt_pin_write(ILI9341_BK_CLK, PIN_HIGH);
    LCD_Clear(WHITE);
    POINT_COLOR=RED;

}
7.整个8080驱动的LCD.C文件完成,写了近1100行代码。
8.使用两路ADC模块,进行光敏电阻和MQ2模块的读取。
static void Adc_entry(void* paremeter)
{
    rt_adc_device_t adc_dev;
    rt_uint32_t value,vol;
    rt_err_t ret = RT_EOK;

    adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
    if (adc_dev == RT_NULL)
    {
        rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
    }
    /* 使能设备 */
    ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
    if(ret == RT_EOK)
    {
        rt_kprintf("adc sample run success!  find %s device!\n", ADC_DEV_NAME);
    }
    while(1)
    {
        /* 读取采样值 */
        value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
        rt_kprintf("the value is :%d \n", value);
        /* 转换为对应电压值 */
        vol = value * REFER_VOLTAGE / CONVERT_BITS;
        rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);

        rt_thread_delay(500);
    }
    /*换算为电压值*/
    txt=vol/100+((vol%100)*0.01);
    /*转换为气体浓度*/
    ppm = pow(11.5428 * 35.904 * txt/(25.5-5.1* txt),0.6549)*10;
9.MQ2模块浓度读取,计算公式附注释。
#define ADC_DEV_NAME2        "adc1"      /* ADC 设备名称 */
#define ADC_DEV_CHANNEL2     9           /* ADC 通道 */

#define REFER_VOLTAGE       330         /* 参考电压 3.3V,数据精度乘以100保留2位小数*/
#define CONVERT_BITS        (1 << 16)   /* 转换位数为16位 */

  
   rt_uint32_t value,vol;
    float txt;
    rt_adc_device_t adc_dev;
    rt_err_t ret = RT_EOK;

    /* 查找设备 */
    adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME2);
    if (adc_dev == RT_NULL)
    {
        rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME2);
        return RT_ERROR;
    }

    /* 使能设备 */
    ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL2);
    /* 读取采样值 */
    value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL2);

    /* 转换为对应电压值 */
    vol = value * REFER_VOLTAGE / CONVERT_BITS;
    /*换算为电压值*/
    txt=vol/100+((vol%100)*0.01);
    /*转换为气体浓度*/
    ppm = pow(11.5428 * 35.904 * txt/(25.5-5.1* txt),0.6549)*10;


    //rt_kprintf("the voltage2 is :%d.%02d \n", vol / 100, vol % 100);

    /* 关闭通道 */
    ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL2);

    return ret;
10.LCD显示中文字符代码, 由于使用横屏模式,所以在取模时需要将字符旋转90度。
void LCD_ShowChinese(uint16_t x,uint16_t y,uint8_t num,uint8_t size,uint8_t mode)
{
    uint8_t temp,t1,t;
    uint16_t y0=y;
    uint16_t colortemp=POINT_COLOR;
    //设置窗口
    num=num-' ';//得到偏移后的值,空格的ascii码是0
    if(!mode) //非叠加方式
    {
        for(t=0;t<size;t++)
        {
           if(size==12)temp=asc2_1206[num][t];  //调用1206字体
           else if(size==16) temp=asc2_1608[num][t];   //调用1608字体
           else if(size==32)  temp=asc2_1616[num][t];      //调用1616汉字字体
           for(t1=0;t1<8;t1++)
           {
               if(temp&0x80)POINT_COLOR=colortemp;
                  else POINT_COLOR=BACK_COLOR;
                  LCD_DrawPoint(x,y);
                  temp<<=1;
                  y++;
                  if(x>=lcddev.width)
                  {
                          POINT_COLOR=colortemp;
                          return;
                  }//超区域了
                if(size==32)
                {
                 if((y-y0)==16)
                 {
                  y=y0;
                  x++;
                  if(x>=lcddev.width){POINT_COLOR=colortemp;return;}//超区域了
                  break;
                 }
                }
                else if((y-y0)==size)
                {
                    y=y0;
                    x++;
                    if(x>=lcddev.width){POINT_COLOR=colortemp;return;}//超区域了
                    break;
                }
           }
        }
    }else//叠加方式
    {
        for(t=0;t<size;t++)
        {
            if(size==12)temp=asc2_1206[num][t];  //调用1206字体
            else if(size==16)temp=asc2_1608[num][t];   //调用1608字体
            else if(size==32)  temp=asc2_1616[num][t];
            for(t1=0;t1<8;t1++)
            {
                if(temp&0x80)LCD_DrawPoint(x,y);
                temp<<=1;
                y++;
                if(x>=lcddev.height){POINT_COLOR=colortemp;return;}//超区域了
                if(size==32)
                {
                    if((y-y0)==16)
                    {
                        y=y0;
                        x++;
                        if(x>=lcddev.width){POINT_COLOR=colortemp;return;}//超区域了
                        break;
                    }
                }
                else if((y-y0)==size)
                {
                    y=y0;
                    x++;
                    if(x>=lcddev.width){POINT_COLOR=colortemp;return;}//超区域了
                    break;
                }
            }
        }
    }
        POINT_COLOR=colortemp;
}

五、开发经验分享

1.开发注意事项

在使用RT-Thread实时操作系统进行多线程应用开发的时候,应该要注意以下事项:

1、RT-Thread的线程调度器是抢占式的,也就是能够保证就绪队列里面,最高优先级的任务总能获得CPU的使用权,在任务设计的时候,要充分考虑好任务的优先级。

2、在硬件中断服务程序运行期间,如果有高优先级的任务就绪,那么被中断的低优先级任务将被挂起,高优先级的任务将会获得CPU的使用权。

3、每个线程都有独立的线程栈,用来保存线程调度时上下文的信息,因此在创建线程分配栈空间的时候,要充分考虑栈的大小。

4、在线程的循环体里面,应该要设置某些条件,在必要的时候主动让出CPU的使用权,特别对于高优先级的线程,如果程序里面有死循环操作而又不主动让出CPU使用权,那么这个线程将会一直占用CPU,并且低优先级的线程永远不会被调度执行。

5、对于没有一直循环执行的线程,线程执行完毕后,资源的回收情况实际上是在空闲线程里面进行的,线程变为关闭状态后,不代表资源马上被回收。

6、系统空闲线程是最低优先级且永远为就绪状态的,空闲线程是一个死循环,永远不会被挂起,但可以被其他高优先级任务抢占,空闲线程主要执行僵尸线程的资源回收工作。

7、空闲线程也可以设置钩子函数,用来进行功耗管理,看门狗喂狗等工作。

8、通过动态方式创建的线程,需要设置好系统堆内存的大小,而通过静态方式创建的线程,线程栈和线程句柄在程序编译的时候就已经确定,不能被动态分配,也不能被释放。

9、大多数线程都是在不断循环执行的,无需进行删除,一般不推荐主动删除线程。线程运行完毕后,系统调度器将会自动把线程加入僵尸队列,资源回收工作将在空闲线程里面进行。

2.开发心得

RT-Thread Studio这个IDE很强大很易用,在使用RT-Thread的时候就不用像之前一样一步一步移植,有了这个软件就可以快速建立包含有RT-Thread的工程。

除此之外,RT-Thread Studio支持开发板开发,也可以很快速的建立工程,甚至可以替换掉keil,而且RT-Thread Studio 支持的开发板和BSp也越来越多,更新得越来越完善,期待未来国产操作系统的精彩亮相,在感受了RT-Thread 强大统治之后,一定要使用ART-Pi不断深入学习RT-Thread 操作系统。

六、产品实物

B站演示视频链接之后会附在尾部哦。视频在这里在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值