ART-Pi is a DIY open source hardware with extended functions specially designed for embedded software engineers and open source makers after half a year of careful preparation by the RT-Thread team.
ART-Pi official websiteOfficial website: ART-Pi (gitee.io)
ART-Pi SDK repository GitHub main repository: RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi (github.com)
First of all, for the purpose of driving the TFT screen, then add a temperature sensor, MQ2 gas sensor and photoresistor to do an environmental monitoring. This is more suitable for in-car monitoring. The MQ2 gas sensor can monitor a variety of harmful gases.
The real thing is as shown in the picture above. The PCB is not too large. It is designed based on the ART-Pi base plate. The pin headers are all Pin to Pin connections because the screen needs to be installed on it, but the photoresistor and MQ2 gas detection module must be external. The only option here is to put half of the screen outside. Let’s see the effect in the picture. It looks good outside. The B boxes are full of O(∩_∩)O as mentioned above, haha~.
Currently, non-16 continuous IO ports are used to simulate 8080 timing, and the 2.8-inch TFT screen is driven through the 8080 protocol. This driver transplant is really laborious. The information on the Internet is all 16 consecutive pins, which can be directly operated by bits. Here is the information Open it up for future reference. The functions currently implemented include temperature and humidity monitoring of DHT11, harmful gas detection of MQ2 gas detection module and light monitoring of photoresistor.
The hardware part is actually quite simple. Of course, the protagonist is our Art-Pi. 16 IO ports are randomly selected as the 8080 protocol pins of the display. At that time, I did not check the ART-Pi manual specifically to connect the 35 37 microphone pins. , so these two pins are currently shared with other peripherals, but I have not enabled other peripherals, so there is no impact. In the future, before drawing the board, you must understand the pins clearly before designing.
In addition to the 8080 bus, the board also has three LED lights, which are used as alarm lights and normal working status lights. I have to say that this violet color SMD LED is really beautiful. In the past, they were all red and green. This time I came into contact with this If you choose a more slutty color, you will have trouble giving gifts to girls in the future O(∩_∩)O haha~.
The interface of the display screen is simple and crude here. Although these IO ports do not support FMC, in order to facilitate labeling, the network label of FMC is still used. This also makes it easier to write the 8080 protocol for control later.
In order to facilitate pin assignment, I specifically checked the schematic diagram of ART-Pi and marked all the IO ports of the 8080 protocol to facilitate transplantation on RT-Thread.
Here is the junior sensor module,
These three sensors are used here as the main monitoring devices.
First, I transplanted the 8080 protocol bus into ART-Pi. Because of the scattered IO ports, bitwise operations cannot be used and I can only use IO ports for operations.
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);
}
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));
}
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;
}
//写数据函数
//可以替代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;
}
//读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;
}
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
",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;
}
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!
", 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!
", ADC_DEV_NAME);
}
while(1)
{
/* 读取采样值 */
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d
", value);
/* 转换为对应电压值 */
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d
", 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;
#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!
", 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
", vol / 100, vol % 100);
/* 关闭通道 */
ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL2);
return ret;
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;
}
When using RT-Thread real-time operating system for multi-threaded application development, you should pay attention to the following matters:
1. The thread scheduler of RT-Thread is preemptive, which means that it can ensure that the highest priority task in the ready queue can always get the right to use the CPU. When designing tasks, the priority of the tasks must be fully considered.
2. During the running of the hardware interrupt service program, if a high-priority task is ready, the interrupted low-priority task will be suspended, and the high-priority task will obtain the right to use the CPU.
3. Each thread has an independent thread stack, which is used to save context information during thread scheduling. Therefore, when creating a thread and allocating stack space, the size of the stack must be fully considered.
4. In the loop body of the thread, certain conditions should be set to actively give up the use of the CPU when necessary. Especially for high-priority threads, if there is an infinite loop operation in the program and the CPU is not actively given up, usage rights, then this thread will always occupy the CPU, and low-priority threads will never be scheduled for execution.
5. For threads that do not continuously execute in a loop, after the thread execution is completed, the resource recycling is actually carried out in the idle thread. After the thread becomes closed, it does not mean that the resources are recycled immediately.
6. The system idle thread has the lowest priority and is always ready. The idle thread is an infinite loop and will never be suspended, but can be preempted by other high-priority tasks. The idle thread mainly performs the resource recovery work of zombie threads. .
7. Idle threads can also set hook functions to perform power consumption management, watchdog feeding, etc.
8. For threads created through dynamic methods, the size of the system heap memory needs to be set. For threads created through static methods, the thread stack and thread handle are determined when the program is compiled and cannot be dynamically allocated or released.
9. Most threads are continuously executed in a loop and do not need to be deleted. It is generally not recommended to actively delete threads. After the thread finishes running, the system scheduler will automatically add the thread to the zombie queue, and resource recycling will be performed in the idle thread.
RT-Thread Studio is a very powerful and easy-to-use IDE. When using RT-Thread, you don’t need to transplant it step by step as before. With this software, you can quickly create a project containing RT-Thread.
In addition, RT-Thread Studio supports development board development and can quickly create projects and even replace keil. Moreover, RT-Thread Studio supports more and more development boards and BSps and is updated more and more. Perfect, I look forward to the wonderful debut of domestic operating systems in the future. After feeling the powerful dominance of RT-Thread, you must use ART-Pi to continue to learn more about the RT-Thread operating system.
The link to the Bilibili demonstration video will be attached at the end. video here
All reference designs on this site are sourced from major semiconductor manufacturers or collected online for learning and research. The copyright belongs to the semiconductor manufacturer or the original author. If you believe that the reference design of this site infringes upon your relevant rights and interests, please send us a rights notice. As a neutral platform service provider, we will take measures to delete the relevant content in accordance with relevant laws after receiving the relevant notice from the rights holder. Please send relevant notifications to email: bbs_service@eeworld.com.cn.
It is your responsibility to test the circuit yourself and determine its suitability for you. EEWorld will not be liable for direct, indirect, special, incidental, consequential or punitive damages arising from any cause or anything connected to any reference design used.
Supported by EEWorld Datasheet