ArtPi基本硬件及需要实现的功能
软件IDE: RT-Thread Studio 版本: 2.1.1 硬件平台: ART-Pi CPU: STM32H750XB 开发板基本外设功能实现:
- 串口 uart4 : PA0 PI9
- Red LED :PC15 低电平 灌电流点亮
- Blue LED: PI8 低电平 灌电流点亮
- User KEY: PH4 硬件上拉
- PWM:PH10(TIM5的通道1)控制蜂鸣器
- TIM硬件定时器使用
- I2C 设备基本操作
- SPI设备基本操作
- CAN设备基本操作
项目工程基于LED闪烁的示例工程建立 ,基于下面的顺序逐步建立测试工程:
- led闪烁
- 按键中断控制 led
- PWM
- RTC
- I2C
- SPI
- WIFI
1. 新建并运行第一个程序
基于模板建立工程 灯闪烁 main.c 中定义LED的引脚为,为蓝灯
#define LEDB_PIN GET_PIN(I, 8)
添加新的引脚红灯:PC15 添加代码:
#define LEDR_PIN GET_PIN(C, 15)
在主程序中添加对应代码,实现红蓝灯闪烁。
/*flip led pin level */
rt_pin_write(LEDB_PIN, !rt_pin_read(LEDB_PIN));
rt_thread_mdelay(200);
/*flip led pin level */
rt_pin_write(LEDR_PIN, !rt_pin_read(LEDR_PIN));
rt_thread_mdelay(200);
按键查询控制灯闪烁:
/*poll key input*/
while(rt_pin_read(USER_KEY) == 0)
{
rt_pin_write(LEDR_PIN, RESET);
}
2.启用ulog以及中断服务程序打印,运行按键中断程序
添加pin中断配置:
/*Config USER_KEY input irq function*/
rt_pin_attach_irq(USER_KEY, PIN_IRQ_MODE_FALLING, user_key_irq_callback, RT_NULL);
/*enable USER_KEY irq*/
rt_pin_irq_enable(USER_KEY, PIN_IRQ_ENABLE);
添加中断回调函数 :
/* Key ISR*/
void user_key_irq_callback()
{
/* log out info */
LOG_D("Button is pushed!\r\n");
}
开启 ulog 服务,添加ulog 配置,注意要勾选使能 log 中断选项,否则运行时会出现以下错误。 [isr错误.jpg)]
[2勾选使能 中断.jpg)]
修改代码
/* enable ulog */
#define LOG_TAG "push_button_app"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
#define LEDB_PIN GET_PIN(I, 8)
#define LEDR_PIN GET_PIN(C, 15)
#define USER_KEY GET_PIN(H, 4)
/* Key ISR*/
void flip_led()
{
/* log out info */
LOG_D("Button is pushed!\r\n");
}
运行结果如下图: [2key中断输入运行结果.png)]
3. PWM输出
使用ART-Pi的PH10(TIM5的通道1)作为PWM输出引脚 [/3使能PWM输出.jpg)]
保存重新编译,下载后,在控制台输入命令: pwm_sample 则PH10输出脉冲宽度变化的波形。
添加beep软件包,实现音乐的播放。这是个有意思的且实现比较简单的项目。 main函数中添加beep初始化代码:
beep_init(NULL, NULL);
添加软件包,并进行配置 [/3beep软件包添加.jpg)]
[/3beep配置.jpg)]
移植 beepplayer,参考 beepplayer 修改使用的PWM引脚: [3beepplay修改引脚.jpg)] 主程序添加代码,就能实现4个曲子顺序播放:
/*beep init*/
beep_player_demo();
4.查看已经在cubemx中配置好的硬件
打开 ioc 文件 ,查看已经配置的外设STM32H750XBH6,如图示 [/4cubemx中的配置.jpg)]
5.RTC工程 开启ALARM
RTT配置 勾选软件模拟 RTC设备, 勾选后,影响红灯闪烁 ,还不知道为什么。 [5RTC配置onchip.jpg)]
[/5RTC配置ALARM.jpg)]
修改stm32h7xx_hal_conf.h board\CubeMX_Config\Core\Inc\stm32h7xx_hal_conf.h将如下一行(大约在69行)取消注释
#define HAL_RTC_MODULE_ENABLED
输入date命令可以看到系统日期,如果未联网就是从2000年1月1日开始 [/5RTC 测试.jpg)]
6. I2C 3 数据传输
I2C引脚配置
[/6I2C引脚配置.jpg)]
编译下载,我们可以看到I2C3 bus已经注册成功,list_device可以看到已经存在了I2C3设备。 [/6i2c3设备注册成功.jpg)]
配置传感器MPU6050 [/6i2cmpu6050配置.jpg)]
编译下载调试运行: [/6mpu6050_probe.jpg)]
[/6mpu6050读数.jpg)]
DS3231 使用,先禁用 内部RTC ,再添加组件
[/6i2c添加ds3231组件.jpg)]
[/6DS3231软件修改i2c地址.jpg)]
[/6i2c-ds3231测试结果.jpg)]
AT24CXX 硬件配置
[/6i2c-24cXX配置.jpg)]
[/6i2c24c02.jpg)]
运行结果 :
\ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Sep 26 2021
2006 - 2020 Copyright by rt-thread team
msh />at24cxx probe i2c3
msh />at24cxx check
[11323] D/I2C: msgs[0] W, addr=0x50, len=2
[11327] D/I2C: msgs[0] R, addr=0x50, len=1
[11331] D/I2C: msgs[0] W, addr=0x50, len=3
[11340] D/I2C: msgs[0] W, addr=0x50, len=2
[11344] D/I2C: msgs[0] R, addr=0x50, len=1
msh />at24cxx write
[16250] D/I2C: msgs[0] W, addr=0x50, len=3
......
[16419] D/I2C: msgs[0] W, addr=0x50, len=3
write ok
msh />at24cxx read
[20488] D/I2C: msgs[0] W, addr=0x50, len=2
......
[20598] D/I2C: msgs[0] R, addr=0x50, len=1
read at24cxx : WELCOM TO RTT
msh />
7. SPI 数据传输
SPI2 连接 ST7789 LCD 添加SPI2设备 [/7添加SPI驱动.jpg)]
在文件 stm32h7xx_hal_msp.c 中,添加对SPI2 的初始化代码,如下图示: [/7添加SPI的初始化代码.jpg)]
else if(hspi->Instance==SPI2) /* ART-Pi SPI LCD的引脚配置 */
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
/**SPI2 GPIO Configuration
PI1 ------> SPI2_SCK
PI2 ------> SPI2_MISO
PI3 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
最后定义: PWR 和 CS 在模块上直接接地,这里连接到了灯上,无用:
#define LCD_DC_PIN GET_PIN(H, 8)
#define LCD_RES_PIN GET_PIN(H, 7)
#define LCD_CS_PIN GET_PIN(C, 15)
#define LCD_PWR_PIN GET_PIN(C, 15)
将 LCD7789 文件夹复制到工程代码中,直接运行会显示之前在小熊派上的显示内容: [7LCD显示%20智慧农业.jpg)]
8.连接网络测试
硬件勾选AP6212,参考 art pi 配置网络 [8配置AP6212.jpg)] 通过wifi join指令连接热点, ping通baidu之后,使用reboot指令重启板卡。 板卡第二次启动之后,在wifi注册完毕之后,自动连接上了之前配置好的热点,不需要在用wifi join指令,直接ping就可以通baidu。
在开发板上使用 WIFI 的时候,每次板子重新上电都要输入 wifi join 命令来实现连接到无线路由器,作为一名程序员来说,能让机器自动做的事情,绝对不会让自己来,所以该例程 art_pi_wifi主要在实现 WIFI 的基本功能之上,增加了断电之后自动重连的功能。 参考ART-PI 连接 ONENET 物联网平台 main函数添加:
extern void wlan_autoconnect_init(void);
......
main()
{
...
/* init Wi-Fi auto connect feature */
wlan_autoconnect_init();
/* enable auto reconnect on WLAN device */
rt_wlan_config_autoreconnect(RT_TRUE);
...
}
9. 移植小熊派的智慧农业工程
查看 E53模块的资料
9.1 E53 相关引脚配置:
- PWM: PH10
- GPIO1 : PA15
- GPIO2: PC6
- GPIO3: PC7
- GPIO4: PD13
- GPIO5: PG7
- USART1 TX RX :PA9 PA10
- I2C3 SCL SDA : PH11 H12
- SPI2 MOSI MISO SCK NSS: PI3 PI2 PI1 PI0
9.2 添加组件
添加onenet软件包后,自动会添加mqtt cjson webclient [9添加onenet软件包.jpg)]
修改onenet详细配置,使能示例: [9onenet详细配置.jpg)]
将自己在 onenet中注册的账号 填入上图的配置 [9mqtt配置api参数等.jpg)]
[9mqtt配置api参数APIkey.jpg)]
#define ONENET_INFO_DEVID "739437824"
#define ONENET_INFO_AUTH "welcome"
#define ONENET_INFO_APIKEY "s2Gei1esFIA9OJQpAp=lu1MzOUc="
#define ONENET_INFO_PROID "442857"
#define ONENET_MASTER_APIKEY "V1xWByMbHofMu4hCq=yjVPZsuuI="
配置好的参数: [9RTT配置好的参数.jpg)]
修改 onenet_sample.c, 全部复制。
9.3 添加传感器 SHT3X
在文件中添加代码: sht3x.c
sht3x_device_t dev_sht30 = RT_NULL;
void E53_IA1_sht30_task_entry(void* par)
{
rt_uint8_t sht_addr = SHT3X_ADDR_PD ;
dev_sht30 = sht3x_init("i2c3", sht_addr);
if(!dev_sht30)
{
rt_kprintf("sht3x probe failed, check input args\n");
}else
{
rt_kprintf("sht3x probed, addr:0x%x\n", sht_addr) ;
}
while(1)
{
if (dev_sht30)
{
/* read the sensor data */
sht3x_read_singleshot(dev_sht30);
// rt_kprintf("sht3x humidity : %d.%d \n", (int)dev_sht30->humidity, (int)(dev_sht30->humidity * 10) % 10);
// rt_kprintf("sht3x temperature: %d.%d \n", (int)dev_sht30->temperature, (int)(dev_sht30->temperature * 10) % 10);
}
else
{
rt_kprintf("Please using 'sht3x probe <i2c dev name> <pu/pd>' first\n");
}
rt_thread_mdelay(1000);
}
}
int E53_IA1_sht30_demo(void)
{
rt_thread_t tid;
tid=rt_thread_create("E53_IA1_sht30_demo", E53_IA1_sht30_task_entry, RT_NULL,2*1024, 20, 7);
if(tid!=RT_NULL)
{
rt_thread_startup(tid);
}
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(E53_IA1_sht30_demo,E53_IA1_sth30 demo);
9.4 添加传感器 BH1750
i添加代码 bh17650.c
#include "sensor.h"
struct rt_sensor_data bh1750_data;
void E53_IA1_bh1750_task_entry(void *par)
{
rt_device_t dev_bh1750=RT_NULL;
dev_bh1750 = rt_device_find("li_bh1750");
if (dev_bh1750 == RT_NULL)
{
rt_kprintf("Can't find li_bh1750 device\n");
return;
}
/* 以只读模式打开bh1750 */
if (rt_device_open(dev_bh1750, RT_DEVICE_FLAG_RDONLY) != RT_EOK)
{
rt_kprintf("open device failed!");
return;
}
while(1)
{
rt_device_read(dev_bh1750, 0, &bh1750_data, 1);
rt_kprintf("BH1750:%4d.%d lux\n", bh1750_data.data.light / 10, bh1750_data.data.light % 10);
rt_thread_mdelay(1000);
}
}
int E53_IA1_bh1750_demo(void)
{
rt_thread_t tid;
tid=rt_thread_create("E53_IA1_bh1750_demo", E53_IA1_bh1750_task_entry, RT_NULL, 2*1024, 20, 6);
if(tid!=RT_NULL)
{
rt_thread_startup(tid);
}
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(E53_IA1_bh1750_demo, E53_IA1_bh1750 demo);
修改传感器的I2C地址: [/11修改BH1750的I2C地址.jpg)]
9.5修改主程序
根据板上的引脚:
- PWM: PH10
- GPIO1 : PA15
- GPIO2: PC6
- GPIO3: PC7
- GPIO4: PD13
- GPIO5: PG7
- USART1 TX RX :PA9 PA10
- I2C3 SCL SDA : PH11 H12
- SPI2 MOSI MISO SCK NSS: PI3 PI2 PI1 PI0
添加主板的4个KEY
- k1: H9
- k2: H15
- k3: H14
- k4: H13
main.c源码 如下
#include "sensor.h"
#include "sht3x.h"
#include "lcd7789/dev_lcd.h"
#include "onenet.h"
#define LED0_PIN GET_PIN(I,8)
#define LED1_PINK_PIN GET_PIN(A,15)
#define MOTOR_PIN GET_PIN(C,7)
#define KEY1_PIN GET_PIN(H,9)
#define KEY2_PIN GET_PIN(H,15)
extern int E53_IA1_sht30_demo(void);
extern int E53_IA1_bh1750_demo(void);
extern int onenet_mqtt_init(void);//初始化onenet
extern int onenet_upload_cycle(void);//循环上报温湿度数据
extern void onenet_upload_entry(void *parameter);//循环上报
extern int onenet_upload_cycle(void);//循环上报任务
extern int onenet_set_cmd_rsp(int argc, char **argv);//接收云端指令信息
extern int cloud_connect_flag;
extern sht3x_device_t dev_sht30;
extern struct rt_sensor_data bh1750_data;
int motor_status;
int led_pink_status;
int motor_flag=0;
int led_flag=0;
int send_flag1=0,send_flag2=0;
void key1_recall(void *args)
{
if(motor_status)
{
rt_pin_write(MOTOR_PIN, PIN_LOW);
motor_flag=0;
}
else {
rt_pin_write(MOTOR_PIN, PIN_HIGH);
motor_flag=1;
}
rt_kprintf("KEY1 test!---\n");
motor_status=~motor_status;
send_flag1=1;
}
void key2_recall(void *args)
{
if(led_pink_status)
{
rt_pin_write(LED1_PINK_PIN, PIN_LOW);
led_flag=0;
}
else {
rt_pin_write(LED1_PINK_PIN, PIN_HIGH);
led_flag=1;
}
rt_kprintf("KEY2 test!+++\n");
led_pink_status=~led_pink_status;
send_flag2=1;
}
int main(void)
{
int count = 1;
/* init Wi-Fi auto connect feature */
wlan_autoconnect_init();
/* enable auto reconnect on WLAN device */
rt_wlan_config_autoreconnect(RT_TRUE);
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);//输出模式
rt_pin_mode(LED1_PINK_PIN, PIN_MODE_OUTPUT);//输出模式
rt_pin_mode(MOTOR_PIN, PIN_MODE_OUTPUT);//输出模式
/*KEY1中断初始化*/
rt_pin_mode(KEY1_PIN , PIN_MODE_INPUT);//输入模式
rt_pin_attach_irq(KEY1_PIN, PIN_IRQ_MODE_FALLING,key1_recall,RT_NULL);//下降沿检测并调用回调函数
rt_pin_irq_enable(KEY1_PIN , PIN_IRQ_ENABLE);//使能中断
/*KEY2中断初始化*/
rt_pin_mode(KEY2_PIN , PIN_MODE_INPUT);//输入模式
rt_pin_attach_irq(KEY2_PIN, PIN_IRQ_MODE_FALLING,key2_recall,RT_NULL);//下降沿检测并调用回调函数
rt_pin_irq_enable(KEY2_PIN , PIN_IRQ_ENABLE);//使能中断
lcd_set_color(WHITE,BLUE);//背景白色,字体蓝色
onenet_mqtt_init();//初始化onenet云平台
E53_IA1_sht30_demo();//E53_IA1智慧农业扩展板温湿度传感器监测任务
E53_IA1_bh1750_demo();//E53_IA1智慧农业扩展板光照强度传感器监测任务
rt_thread_mdelay( RT_TICK_PER_SECOND );
onenet_set_cmd_rsp(RT_NULL, RT_NULL);//启动接收接收云平台指令并解析进行控制
onenet_upload_cycle();//循环上报数据到云平台任务
while (count++)
{
lcd_show_string(180, 60, 32, "%2d% ",(int)dev_sht30->humidity);//湿度数据LCD显示
lcd_show_string(60, 60, 32, "%d.%d",(int)dev_sht30->temperature,(int)(dev_sht30->temperature*10)%10);//温度数据LCD显示
lcd_show_string(60, 125, 32, "%4d",bh1750_data.data.light / 10);//光照强度数据LCD显示
/*通过上传数据到云平台成功来判断是否上云成功*/
if(cloud_connect_flag==1)
{
lcd_set_color(GREEN,BLUE);
lcd_show_string(140, 125, 32, "OneNET");
lcd_set_color(WHITE,BLUE);
}else {
lcd_set_color(RED,YELLOW);
lcd_show_string(140, 125, 32, "OneNET");
lcd_set_color(WHITE,BLUE);
}
/*E53_IA1 电机运行开关状态显示*/
if(motor_flag==1)
{
lcd_set_color(BLUE,GREEN);
lcd_show_string(10, 210, 24, "FAN:ON ");
lcd_set_color(WHITE,BLUE);
}else if(motor_flag==0)
{
lcd_set_color(BLUE,RED);
lcd_show_string(10, 210, 24, "FAN:OFF ");
lcd_set_color(WHITE,BLUE);
}
/*E53_IA1 LED紫色灯开关状态显示*/
if(led_flag==1)
{
lcd_set_color(BLUE,GREEN);
lcd_show_string(140, 210, 24, "LED:ON ");
lcd_set_color(WHITE,BLUE);
}else if(led_flag==0)
{
lcd_set_color(BLUE,RED);
lcd_show_string(140, 210, 24, "LED:OFF");
lcd_set_color(WHITE,BLUE);
}
if(send_flag1==1)//将本地按键控制状态上传到云平台来判定控制的设备:E53_IA1智慧农业扩展板电机
{
send_flag1=0;
if(onenet_mqtt_upload_digit("Motor_status", motor_flag))
{
LOG_E("upload has an error, stop uploading");
}else {
LOG_D("buffer : {\"Motor_status\":%d}",motor_flag);
}
}
if(send_flag2==1)//将本地按键控制状态上传到云平台来判定控制的设备:E53_IA1智慧农业扩展板LED紫色灯
{
send_flag2=0;
if(onenet_mqtt_upload_digit("LED_status", led_flag))
{
LOG_E("upload has an error, stop uploading");
}else {
LOG_D("buffer : {\"LED_status\":%d}",led_flag);
}
}
/*板载蓝灯闪烁*/
rt_pin_write(LED0_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED0_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
return RT_EOK;
}
最后打开云端的应用,具体流程,和 onenet_sample.c. 源码参考基于RT-Thread Studio 和小熊派 实现智慧农业 [11智慧农业测试平台.jpg)]
智慧农业演示结果 最终测试结果:传感器加上音乐播放的视频
|