【开发环境】
1、硬件:cw32l083vxtx startkit 开发板,板载有8位lcd段码屏。
2、软件环境:mdk5。
3、温湿度计:sht30。
【硬件连接】
开发板 sht30
pb11 sda
pb10 scl
dvcc vcc
dvss gnd
【功耗测试环境】
合宙iot power功耗测试神器。
【硬件框图】
【软件流程图】
【主要代码设计】
本工程主要代码功能为温湿传感器sht30的数据采集、lcd显示、rtc自动唤醒。下面展示三个功能模块的主要代码:
1、sht30采集模拟iic通信,主要是iic的时序产生,与sht30的单次采集指令发送与数据读取以及crc。
iic的时序产生主要代码如下:
void iic_init(void)
{
//配置pb10 为输出
//使能gpiob时钟
cw_sysctrl->ahben_f.gpiob = 1;
//配置pb10 为输出
cw_gpiob->analog_f.pin10 = 0; //设置 gpiox_analog.piny 为 0,将端口配置为数字功能;
cw_gpiob->dir_f.pin10 = 0; //设置 gpiox_dir.piny 为 0,将端口配置成输出;
cw_gpiob->opendrain_f.pin10 = 0; //0:推挽输出
cw_gpiob->odr_f.pin10 = 1;
cw_gpiob->analog_f.pin11 = 0; //设置 gpiox_analog.piny 为 0,将端口配置为数字功能;
cw_gpiob->dir_f.pin11 = 0; //设置 gpiox_dir.piny 为 0,将端口配置成输出;
cw_gpiob->opendrain_f.pin11 = 0; //0:推挽输出
cw_gpiob->odr_f.pin11 = 1;
}
//io方向设置(sda)
/ xxxxxxxxxxxxxx ****/
void sda_in()
{
cw_gpiob->dir_f.pin11 = 1; //设置 gpiox_dir.piny 为 0,将端口配置成输出;
}
void sda_out()
{
cw_gpiob->dir_f.pin11 = 0; //设置 gpiox_dir.piny 为 0,将端口配置成输出;
cw_gpiob->opendrain_f.pin11 = 0; //0:推挽输出
}
//产生iic起始信号
void iic_start(void)
{
sda_out(); //sda线输出
iic_sda=1;
iic_scl=1;
delay_us(4);
iic_sda=0;//start:when clk is high,data change form high to low
delay_us(4);
iic_scl=0;//钳住i2c总线,准备发送或接收数据
}
//产生iic停止信号
void iic_stop(void)
{
sda_out();//sda线输出
iic_scl=0;
iic_sda=0;//stop:when clk is high data change form low to high
delay_us(4);
iic_scl=1;
iic_sda=1;//发送i2c总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
/ xxxx修改超时时间 ***/
uint8_t iic_wait_ack(void)
{
uint8_t ucerrtime=0;
sda_in(); //sda设置为输入
iic_sda=1;delay_us(3);
iic_scl=1;delay_us(3);
while(read_sda)
{
ucerrtime++;
if(ucerrtime>250)
{
//printf(超时
);
iic_stop();
return 1;
}
}
iic_scl=0;//时钟输出0
return 0;
}
//产生ack应答
void iic_ack(void)
{
iic_scl=0;
sda_out();
iic_sda=0;
delay_us(2);
iic_scl=1;
delay_us(2);
iic_scl=0;
}
//不产生ack应答
void iic_nack(void)
{
iic_scl=0;
sda_out();
iic_sda=1;
delay_us(2);
iic_scl=1;
delay_us(2);
iic_scl=0;
}
//iic发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void iic_send_byte(uint8_t txd)
{
uint8_t t;
sda_out();
iic_scl=0;//拉低时钟开始数据传输
for(t=0;t>7)
iic_sda=1;
else
iic_sda=0;
txd<<=1;
delay_us(2); //对tea5767这三个延时都是必须的
iic_scl=1;
delay_us(2);
iic_scl=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ack,ack=0,发送nack
uint8_t iic_read_byte(unsigned char ack)
{
unsigned char i,receive=0;
sda_in();//sda设置为输入
for(i=0;i<8;i++ )
{
iic_scl=0;
delay_us(100);
iic_scl=1;
receive<<=1;
if(read_sda)receive++;
delay_us(100);
}
if (!ack)
iic_nack();//发送nack
else
iic_ack(); //发送ack
return receive;
}
sht30的测量指令与数据获取及crc主要代码如下:
#include sht30.h
#define polynomial_cxdz 0x31 // x^8 + x^5 + x^4 + 1
//sht3x crc校验
unsigned char sht3x_crc(uint8_t *data, uint8_t len)
{
unsigned char bit; // bit mask
unsigned char crc = 0xff; // calculated checksum
unsigned char bytectr; // byte counter
// calculates 8-bit checksum with given polynomial @gzcxdz
for(bytectr = 0; bytectr 0; --bit) {
if(crc & 0x80) {
crc = (crc << 1) ^ polynomial_cxdz;
} else {
crc = (crc 8)&0xff); //msb
iic_wait_ack();
iic_send_byte(cmd&0xff); //lsb
iic_wait_ack();
iic_stop();
systickdelay(500);//命令发完后需要等待20ms以上才能读写
}
//sht30读取温湿度
//temp:温度,-400~1250,实际温度=temp/10,分辨率0.1℃,精度±0.3℃
//humi:湿度,0~1000,实际湿度=humi/10,分辨率0.1%rh,精度±3
//返回0成功,1失败
uint8_t sht30_read_humiture(int *temp,uint16_t *humi)
{
uint8_t buff[6];
sht30_cmd(sht30_read_humiture);//读温湿度命令
iic_start();
iic_send_byte(sht30_addr+1); //发送设备地址,读寄存器
iic_wait_ack();
buff[0]=iic_read_byte(1);//继续读,给应答
buff[1]=iic_read_byte(1);//继续读,给应答
buff[2]=iic_read_byte(1);//继续读,给应答
buff[3]=iic_read_byte(1);//继续读,给应答
buff[4]=iic_read_byte(1);//继续读,给应答
buff[5]=iic_read_byte(0);//不继续给停止应答
iic_stop();
//printf(buff=%d,%d,%d,%d,%d,%d
,buff[0],buff[1],buff[2],buff[3],buff[4],buff[5]);
//crc校验
if(sht3x_crc(&buff[0],2)==buff[2] && sht3x_crc(&buff[3],2)==buff[5])
{
temp=(-45+(175.0 ((buff[0]<<8)+buff[1])/65535.0)) *10;
humi=10100* ((buff[3]<1250) *temp=1250;
else if(*tempram0 = 0;
cw_lcd->ram1 = 0;
cw_lcd->ram8 = 0;
cw_lcd->ram9 = 0;
}
void show_nums(uint32_t num)
{
uint8_t i=0;
uint8_t j;
uint32_t temp;
temp = num;
//空显示
lcd_clear();
if(temp == 0)
show_num(0,0,0);
while(temp>0)
{
j = temp%10;
show_num(i,j,0);
temp /=10;
i++;
}
}
/**
*功能:显示数字到lcd段码屏上
*输入参数1:显示在哪个位上7-0
*输入参数2:需要显示数字
*输入参数3:是否需要显示小数点
*/
void show_num(uint8_t wei, uint8_t num, uint8_t doit)
{
uint8_t temp_h;
temp_h = num_h[num];
if(0 != doit)
{
temp_h = temp_h + 8 ; //第四位置1显示小数点
}
switch(wei)
{
case 7:
{
//显示第7个数码管
cw_lcd->ram0 |= temp_h
break;
}
case 4:
{
//显示第4个数码管
cw_lcd->ram8 |= temp_h<<16 | num_l[num]cw_lcd->ram2 = 0;
cw_lcd->ram3 = 0;
cw_lcd->ram4 = 0;
cw_lcd->ram5 = 0;
cw_lcd->ram6 = 0;
cw_lcd->ram7 = 0;
cw_lcd->ram8 = 0;
cw_lcd->ram9 = 0;
cw_lcd->ram10 = 0;
cw_lcd->ram11 = 0;
cw_lcd->ram12 = 0;
cw_lcd->ram13 = 0;
lcd_cmd(enable);
cw_lcd->ram0 = 0;
lcd_contrastconfig(lcd_contrast_level_6);
lcd_drivevoltageconfig(lcd_inrs_level_0);
}
3、功耗控制主要是通过进入深度睡眠模式来实现节能,并通过rtc的awt模块来实现定时唤醒。在此模块中,我们配置了awt时钟源为rtc_awtsource_from_rtc1hz_1即1秒为单位的唤醒,我们可以通过rtc_awtarr 唤醒定时器重载值,来实现以秒为单位的休眠时长。主要代码如下:
//进入低功耗设置
void entry_power(void)
{
// //1,先判断是否上电复位
rtc_inittypedef rtc_initstruct = {0};
rtc_awttypedef rct_awtstruct = {0};
rcc_lse_enable(rcc_lse_mode_osc, rcc_lse_amp_normal, rcc_lse_driver_normal); // 选择lse为rtc时钟
rtc_initstruct.datestruct.day = 0x24; //设置日期,day、month、year必须为bcd方式,星期为0~6,代表星期日,星期一至星期六
rtc_initstruct.datestruct.month = rtc_month_june;
rtc_initstruct.datestruct.week = rtc_weekday_monday;
rtc_initstruct.datestruct.year = 0x23;
rtc_initstruct.timestruct.hour = 0x11; //设置时间,hour、miniute、second必须为bcd方式,用户须保证hour、ampm、h24之间的关联正确性
rtc_initstruct.timestruct.minute = 0x58;
rtc_initstruct.timestruct.second = 0x59;
rtc_initstruct.timestruct.ampm = 0;
rtc_initstruct.timestruct.h24 = 0;
rtc_initstruct.rtc_clocksource = rtc_rtcclk_from_lse;
rtc_init(&rtc_initstruct); //
//设置自动唤醒
rct_awtstruct.awt_clocksource = rtc_awtsource_from_rtc1hz_1;
rct_awtstruct.awt_arrvalue = 60;
rtc_awtconfig(&rct_awtstruct);
rtc_awtcmd(enable);
rcc_apbperiphclk_enable1(rcc_apb1_periph_rtc, enable);
rtc_itconfig(rtc_it_awtimer, enable);
}
4、在主程序中,我们先初始基本外设后进行循环的采集——显示——休眠——唤醒来实现温湿度采集的目标,主程序主要代码如下:
int32_t main(void)
{
uint16_t temp;
int t[20];
uint16_t h[20];
rcc_configuration();
nvic_configuration();
lcd_configuration();
inittick(8000000);
sht30_init();
lcd_clear();
scb->scr |= scb_scr_sleepdeep_msk;
entry_power();
while(1)
{
sht30_read_humiture(t,h);
temp = t[0];
lcd_clear();
show_num(2, temp/100,0);
show_num(1, (temp/10)%10,1);
show_num(0, temp%10,0);
temp = h[0];
show_num(7, temp/100,0);
show_num(6, (temp/10)%10,1);
show_num(5, temp%10,0);
cw_sysctrl->ahben_f.gpiob = 0;
__dsb();
__wfi();
sht30_init();
}
}
【实现的效果】
我们设定60秒中唤醒进行一次温显度采集,实现了休眠电流为5ua,综合平均工作电流为13ua、平均功率为。基本满足了以电池供电的环境下的超长工作。
【讨论】
cw32l083集成了lcd控制器,可以实现数据采集、显示的超低功耗工作。非常适合用于电池供电的环境下工作。本次试验虽然获得了理想效果,但是还有一些可以改进的地方。
1、在待机中的主要电流产生是lcd屏产生的功耗,如果在特殊的环境下,不需要长时间显示,可以适时关闭lcd屏,这样可以节约差不多4ua的工作电流。启用按键来人工参与显示数据,这样又可以更进一步降低超机功耗。
2、在工作电流中,主要消耗的是sht30的温度转换时产生的大电流。如果应用的生产环境,可以在等待温度转换时,降低mcu的主频或者进入sleep模式以降低能耗。
[[]()]()
华为消息:华为提前终止对澳橄榄球队赞助 摇摆不定的法国新表态
百度云FPGA云服务器发布内测版本_助力人工智能和大数据应用
飞凌嵌入式FETA40i-C核心板简介
相控阵天线方向图——第2部分:栅瓣和波束斜视
CRM客户管理系统为企业发展赋能
基于CW32L083设计的超低功耗温湿度计
电力设备节能数据采集远程监控系统解决方案
采用CPLD的多次重触发存储测试系统的实现
154BSD001BA-5BICT数字压力传感器的规格
模块化手机要来了!Moto Z国行售价上市时间已定
海洋生物栖息地监测方案采用了3D视觉相机技术
Apple Watch正式亮相,功能终见多样化
如何学习单片机嵌入式?
隆利科技“用于显示的发光二极管”获发明专利证书
华大九天前三季净利同比增逾5成,我国科学家研发超高速光电计算芯片
为什么数字对讲机出现串频现象几率为零?
台积电将购入18台EUV光刻机!
量化交易软件开发数字资产自动化交易系统开发
智慧城市的发展离不开智慧消防管理云平台系统的助力
如何使用TMT4 PCIe性能综合测试仪创建PCIe参考模板?(附白皮书下载)