本帖最后由 yuyy1989 于 2023-6-1 14:34 编辑
2.3 安装AutoChips.AC7802x_DFP.1.0.0.pack 3.6 SPI驱动LCD屏幕 3.7 I2C读取DHTC12 4.恒温恒湿控制箱模拟实现 1.开箱晒图 开发板已收到,发的是京东快递,这盒子真不错
相比盒子来说板子就显得比较小了
2.搭建开发环境 2.1 下载开发资料,直接从活动贴里下载就行,都打包在一起了,本来也想这里也放一份方便下载,但是上传不了那么大的文件,放上活动贴链接吧https://bbs.21ic.com/icview-3299664-1-1.html
如果想去官网下载,进这个链接https://www.autochips.com/developersr.html?ty=73&tty=79
解压出来内容如图
建议先看一下开发板资料里的AC7802x 开发板入门指南.pdf
2.2 下载MDK并安装https://www.keil.com/download/product/
2.3 打开AC7802x开发板资料包CMSIS文件夹中的AutoChips.AC7802x_DFP.1.0.0.rar,双击AutoChips.AC7802x_DFP.1.0.0.pack安装
正确安装后在keil中可以看到AC7802x系列的芯片
随便打开一个例程进行编译,可以编译成功说明开发环境搭建成功
3.例程基础实验 3.1 按键点灯实现点击按键切换2个LED交替亮起
查看AC7802x 开发板入门指南.pdf找到LED和按键用到的IO
复制一个例程,基于这个例程改动,这里复制的是01_GPIO_Basic
改动后的代码
#include "ac780x_gpio.h"
#define LED1PORT GPIOA
#define LED1PIN GPIO_PIN2
#define LED2PORT GPIOA
#define LED2PIN GPIO_PIN3
#define KEYPORT GPIOA
#define KEYPIN GPIO_PIN11
void test_setled1onoff(uint8_t on)
{
if(on)
GPIO_SetPinLevel(LED1PORT, LED1PIN, GPIO_LEVEL_HIGH);
else
GPIO_SetPinLevel(LED1PORT, LED1PIN, GPIO_LEVEL_LOW);
}
uint8_t test_getled1state(void)
{
if(GPIO_GetPinLevel(LED1PORT, LED1PIN) == GPIO_LEVEL_HIGH)
return 1;
return 0;
}
void test_setled2onoff(uint8_t on)
{
if(on)
GPIO_SetPinLevel(LED2PORT, LED2PIN, GPIO_LEVEL_HIGH);
else
GPIO_SetPinLevel(LED2PORT, LED2PIN, GPIO_LEVEL_LOW);
}
uint8_t test_getled2state(void)
{
if(GPIO_GetPinLevel(LED2PORT, LED2PIN) == GPIO_LEVEL_HIGH)
return 1;
return 0;
}
void test_ledinit(void)
{
GPIO_SetFunc(LED1PORT, LED1PIN, GPIO_FUN0);/*功能复用选择.*/
GPIO_SetFunc(LED2PORT, LED2PIN, GPIO_FUN0);
/*设置LED引脚为GPIO输出.*/
GPIO_SetDir(LED1PORT, LED1PIN, GPIO_OUT);
GPIO_SetDir(LED2PORT, LED2PIN, GPIO_OUT);
}
void test_keyinit(void)
{
GPIO_SetFunc(KEYPORT, KEYPIN, GPIO_FUN0); /*功能复用选择.*/
/*设置按键引脚为输入,检测按键动作.*/
GPIO_SetDir(KEYPORT, KEYPIN, GPIO_IN); /*设置为输入模式.*/
}
void test_prockey(void)
{
if(GPIO_GetPinLevel(KEYPORT, KEYPIN) == GPIO_LEVEL_LOW)
{
mdelay(30);
if(GPIO_GetPinLevel(KEYPORT, KEYPIN) == GPIO_LEVEL_LOW)
{
while(GPIO_GetPinLevel(KEYPORT, KEYPIN) == GPIO_LEVEL_LOW);
test_setled1onoff(!test_getled1state());
test_setled2onoff(!test_getled2state());
}
}
}
int main(void)
{
InitDelay();
test_ledinit();
test_keyinit();
test_setled1onoff(1);
test_setled2onoff(0);
while (1)
{
test_prockey();
}
}
编译烧录,烧录前注意选择自己使用的烧录器,建议勾选上Reset and run选项
运行效果
3.2 UART串口通信
这个板子自带了USB转串口,通过Type-C数据线连接时,会出现一个串口设备
打开例程02_UART_Interrupt,查看串口配置
查看原理图可以看到所用IO和板载的USB转串口使用的IO一致
编译烧录,打开串口助手,配置好参数,发送字符串会返回和发送相同的字符串
下面把串口通讯代码合并到点灯的程序里,实现串口命令控制点灯
在串口空闲中断里添加代码
if(g_rxBuf[0] == 'L' && g_rxBuf[1] == 'E' && g_rxBuf[2] == 'D')
{
if(g_rxBuf[3] == '1')
{
if(g_rxBuf[4] == '0')
{
test_setled1onoff(0);
}
else if(g_rxBuf[4] == '1')
{
test_setled1onoff(1);
}
}
else if(g_rxBuf[3] == '2')
{
if(g_rxBuf[4] == '0')
{
test_setled2onoff(0);
}
else if(g_rxBuf[4] == '1')
{
test_setled2onoff(1);
}
}
}
运行效果
3.3 PWM实现呼吸灯
开发板上的2个LED可以用PWM驱动,基于例程里的PWM示例,做一个两个灯珠交替呼吸的程序
#include "ac780x_gpio.h"
#include "ac780x_pwm.h"
#include "ac780x_pwm_reg.h"
void test_pwm_Init(void)
{
PWM_ConfigType config;
PWM_ModulationConfigType pwmConfig;
PWM_IndependentChConfig independentChConfig[2];
memset(&config, 0U, sizeof(config));
memset(&pwmConfig, 0U, sizeof(pwmConfig));
memset(&independentChConfig, 0U, sizeof(independentChConfig));
GPIO_SetFunc(GPIOA, GPIO_PIN2, GPIO_FUN1); /* PA2--PWM2_CH1.*/
GPIO_SetFunc(GPIOA, GPIO_PIN3, GPIO_FUN1); /* PA3--PWM2_CH0.*/
/*
边沿对齐PWM模式:
周期=(MCVR-CNTIN+1)*PWM计数器时钟周期
脉宽=(CHnV-CNTIN+1)*PWM计数器时钟周期
中心对齐PWM模式:
周期=2*(MCVR-CNTIN)*PWM计数器时钟周期
脉宽=2*(CHnV-CNTIN)*PWM计数器时钟周期
*/
independentChConfig[0].channel = PWM_CH_0; /*独立输出通道选择 */
independentChConfig[0].chValue = 0; /*通道channel值,决定占空比 */
independentChConfig[0].levelMode = PWM_HIGH_TRUE; /*输出PWM高有效,可配置高有效或低有效 */
independentChConfig[0].polarity = PWM_OUTPUT_POLARITY_ACTIVE_HIGH; /*通道输出极性配置为高有效,PWM Mask后输出为低电平 */
independentChConfig[0].interruptEn = ENABLE; /*通道匹配中断使能位 */
independentChConfig[0].initLevel = PWM_LOW_LEVEL; /*通道初始电平输出配置,该配置受initChOutputEn控制,决定PMM计数器未工作前PWM口的输出电平 */
independentChConfig[0].triggerEn = DISABLE; /*通道匹配触发使能位,在通道值匹配时可产生触发信号用于其他模块的触发信号 */
independentChConfig[1].channel = PWM_CH_1; /*独立输出通道选择 */
independentChConfig[1].chValue = 0; /*通道channel值,决定占空比 */
independentChConfig[1].levelMode = PWM_HIGH_TRUE; /*输出PWM高有效,可配置高有效或低有效 */
independentChConfig[1].polarity = PWM_OUTPUT_POLARITY_ACTIVE_HIGH; /*通道输出极性配置为高有效,PWM Mask后输出为低电平 */
independentChConfig[1].interruptEn = ENABLE; /*通道匹配中断使能位 */
independentChConfig[1].initLevel = PWM_LOW_LEVEL; /*通道初始电平输出配置,该配置受initChOutputEn控制,决定PMM计数器未工作前PWM口的输出电平 */
independentChConfig[1].triggerEn = DISABLE; /*通道匹配触发使能位,在通道值匹配时可产生触发信号用于其他模块的触发信号 */
pwmConfig.countMode = PWM_UP_DOWN_COUNT; /*PWM计数器模式,PWM_UP_COUNT--向上计数模式;PWM_UP_DOWN_COUNT-- 向上/向下计数模式 */
pwmConfig.independentChannelNum = 2; /*独立通道数目*/
pwmConfig.combineChannelNum = 0; /*组合通道对数 */
pwmConfig.independentChConfig = independentChConfig; /*独立通道配置赋值 */
pwmConfig.combineChConfig = NULL; /*组合通道配置赋值 */
pwmConfig.deadtime = 0; /*死区时间值,死区功能仅在组合模式下有效 */
pwmConfig.deadtimePsc = PWM_DEADTIME_DIVID_1; /*死区时间时钟分频系数,死区功能仅在组合模式下有效 */
pwmConfig.initChOutputEn = ENABLE; /*初始化通道输出使能位,使能后独立PWM模式的 initLevel 和组合模式的ch1stInitLevel和ch2ndInitLevel配置才会生效*/
pwmConfig.initTriggerEn = DISABLE; /*PWM初始值触发使能位 */
/*
向上-向下技术模式下,频率计算为:
freq = pwm_clk/(2*(maxValue - initValue))
16000/(2*8000) = 1K
*/
config.mode = PWM_MODE_MODULATION; /*PWM模式配置,PWM_MODE_MODULATION--PWM调制模式 */
config.initModeStruct = &pwmConfig; /*不同模式相应初始化配置结构体赋值 */
config.clkSource = PWM_CLK_SOURCE_APB; /*PWM时钟源选择 */
config.clkPsc = 0; /*时钟分频系数 */
config.initValue = 0; /*初始计数值 */
config.maxValue = 8000; /*最大计数值,决定输出波形频率 */
config.overflowInterrupEn = ENABLE; /*溢出中断使能位 */
config.cntOverflowFreq = 0; /*溢出中断产生的频率与计数器频率的关系,0表示每次计数器溢出都产生中断,1表示间隔一次,以此类推 */
config.interruptEn = ENABLE; /*PWM总中断使能位 */
//config.callBack = PWM2_Callback; /*中断回调函数 */
PWM_Init(PWM2, &config);
}
int main(void)
{
uint16_t pwm = 0;
uint8_t pwmup = 1;
InitDelay();
while (1)
{
mdelay(2);
PWM_SetChannelCountValue(PWM2,0,8000 - pwm);
PWM_SetChannelCountValue(PWM2,1,pwm);
if(pwmup > 0)
{
if(pwm < 8000 - 10)
{
pwm += 10;
}
else
{
pwm = 8000;
pwmup = 0;
}
}
else
{
if(pwm > 10)
{
pwm -= 10;
}
else
{
pwm = 0;
pwmup = 1;
}
}
}
}
运行效果
3.4 通过ADC实现使用电位器控制LED亮度
开发板上有个可调电位器,用它来实现旋转旋钮调节LED亮度
#include "ac780x_gpio.h"
#include "ac780x_pwm.h"
#include "ac780x_pwm_reg.h"
#include "ac780x_adc_reg.h"
void test_pwm_Init(void)
{
//省略,参考上个例程
}
void test_adc_init(void)
{
ADC_ConfigType adcConfig; /*! ADC初始化配置*/
memset(&adcConfig, 0x00, sizeof(adcConfig)); /*! 清空结构体*/
/*! ADC输入端口(电位器)配置*/
GPIO_SetFunc(GPIOA, GPIO_PIN10, GPIO_FUN2); /*! PA10复用为FUN2,为ADC_IN1 ,对应电位器VR1*/
/*! ADC配置
ADC固定为12位分辨率,工作模式为MODE1(工作模式内容见参考手册8.4.2章节),规则组扫描+注入组扫描模式多通道单次转换,规则组长度为3,注入组长度为0
每触发一次进行一次ADC转换,每次转换规则组中的3个通道。
*/
adcConfig.clkPsc = ADC_CLK_PRESCALER_2; /*! ADC时钟分频设置,Set ADC Clk = APB时钟频率/(clkPsc + 1) = 16M/2 = 8M */
adcConfig.scanModeEn = DISABLE; /*! 模式配置SCAN:扫描模式使能位 多通道需使能扫描模式,单通道则不需要使能*/
adcConfig.continuousModeEn = DISABLE; /*! 模式配置CONT:连续模式使能位 0:触发一次后只转换一次,1:触发后可连续转换*/
adcConfig.regularDiscontinuousModeEn = DISABLE; /*! 模式配置DISCEN:打开规则组间断转换模式*/
adcConfig.injectDiscontinuousModeEn = DISABLE; /*! 模式配置IDISEN:打开注入组间断转换模式*/
adcConfig.injectAutoModeEn = DISABLE; /*! 模式配置IAUTO:自动注入模式*/
adcConfig.intervalModeEn = DISABLE; /*! 模式配置INTERVAL:注入组为间隔转换模式*/
adcConfig.regularDiscontinuousNum = 0; /*! 规则组子组长度,用于Mode7和Mode8*/
adcConfig.interruptEn = DISABLE; /*! 总中断使能*/
adcConfig.voltageRef = ADC_VOLTAGEREF_VDDA; /*! ADC参考源选择 */
adcConfig.regularTriggerMode = ADC_TRIGGER_INTERNAL; /*! 规则组触发源类型选择*/
adcConfig.injectTriggerMode = ADC_TRIGGER_INTERNAL; /*! 注入组触发源类型选择*/
adcConfig.regularSequenceLength = 3; /*! 规则组长度*/
adcConfig.injectSequenceLength = 0; /*! 注入组长度*/
adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT; /*! 数据右对齐*/
adcConfig.callBack = NULL; /*! ADC回调函数*/
adcConfig.powerMode = ADC_POWER_ON; /*! ADC上电*/
ADC_Init(ADC0, &adcConfig); /*! ADC works Mode Config*/
/*!
ADC转换率计算公式:
总转换时间=(SPT+ 12)/ADC时钟频率+5个APB时钟周期
备注:
1.SPT为采样周期个数,具体见下面ADC_SPT_CLK_x。
2.ADC时钟频率 = APB时钟频率 /(分频系数+1)
3.7802x ADC支持的最高采样率为250Ksps(即转换时间不低于4us),如果配置采样率高于该值,可能会导致采样结果精度显著减低。
*/
/*规则组通道转换序列和转换速率配置*/
ADC_SetRegularGroupChannel(ADC0, ADC_CH_1, ADC_SPT_CLK_33, 0); /*! 采样&转换时间= (33+12)/8000000 + 5/16000000 ≈ 5.94us */
/*! Bandgap或T-sensor内部通道配置*/
ADC_SetInternalChannel(ADC0, ADC_INTERNAL_TSENSOR); /*! 内部电压信号选择(仅在使用了ADC_CH_VIN 时配置) */
ADC_SetVBufEnableFlag(ADC0, ENABLE); /*! Bandgap和T-sensor内部通道使能(仅在使用了ADC_CH_VIN 时配置) */
}
uint16_t test_getadc(void)
{
uint16_t adcvalue = 0;
ADC_SoftwareStartRegularConvert(ADC0); /*! 软件触发规则组采样*/
while (!ADC_GetEOCFlag(ADC0, 0)); /*! 等待规则组最后一个通道转换完成*/
adcvalue = ADC_GetRegularData(ADC0, 0); /*! 获取规则组0的转换值*/
return adcvalue;
}
int main(void)
{
uint16_t pwm = 0;
InitDelay();
test_adc_init();
test_pwm_Init();
while (1)
{
mdelay(10);
pwm = test_getadc()*8000/4095;
PWM_SetChannelCountValue(PWM2,0,8000 - pwm);
PWM_SetChannelCountValue(PWM2,1,pwm);
}
}
运行效果
3.5 定时器测试
用定时器实现两个LED交替闪烁
#include "ac780x_gpio.h"
#include "ac780x_timer.h"
#define Timer_CLK (APB_BUS_FREQ) /*!定时器时钟为APB时钟 */
#define TimeoutS(n) (Timer_CLK*n - 1) /*!n 秒超时值 */
#define Timeout1ms (Timer_CLK/1000-1) /*!1ms超时值 */
#define Timeout500ms (Timer_CLK/2-1) /*!500ms超时值 */
//LED相关函数省略
void test_timer_cb(void *device, uint32_t wpara, uint32_t lpara)
{
test_setled1onoff(!test_getled1state());
test_setled2onoff(!test_getled2state());
}
void test_timer_init()
{
TIMER_ConfigType timerConfig;
memset(&timerConfig, 0, sizeof(timerConfig));
/*!配置定时器.*/
timerConfig.periodValue = Timeout500ms; /*! 定义超时值为500ms */
timerConfig.linkModeEn = DISABLE; /*! 禁能链接模式 */
timerConfig.interruptEn = ENABLE; /*! 使能定时器中断 */
timerConfig.timerEn = ENABLE; /*! 打开定时器 */
timerConfig.callBack = test_timer_cb; /*! 中断回调函数 */
TIMER_Init(TIMER_CHANNEL0, &timerConfig); /*! TIMER初始化函数生效 */
}
int main(void)
{
InitDelay();
test_ledinit();
test_timer_init();
while (1)
{
}
}
运行效果
3.6 SPI驱动LCD屏幕以前用别的芯片驱动过,文件复制过来改一下SPI通讯部分就行了,放上移植修改的代码,软硬件SPI都能用
/*
MOSI PB3
SCK PB5
CS PA7
RST PA8
A0 PA9
*/
#define YUYY_USE_SOFT_SPI 0
void yuyy_hs12864g18b_spiinit(void)
{
GPIO_SetFunc(GPIOA, GPIO_PIN7, GPIO_FUN0);/*功能复用选择.*/
GPIO_SetFunc(GPIOA, GPIO_PIN8, GPIO_FUN0);
GPIO_SetFunc(GPIOA, GPIO_PIN9, GPIO_FUN0);
GPIO_SetDir(GPIOA, GPIO_PIN7, GPIO_OUT);
GPIO_SetDir(GPIOA, GPIO_PIN8, GPIO_OUT);
GPIO_SetDir(GPIOA, GPIO_PIN9, GPIO_OUT);
GPIO_SetPinLevel(GPIOA, GPIO_PIN6, GPIO_LEVEL_HIGH);
GPIO_SetPinLevel(GPIOA, GPIO_PIN8, GPIO_LEVEL_HIGH);
#if(YUYY_USE_SOFT_SPI)
GPIO_SetFunc(GPIOB, GPIO_PIN5, GPIO_FUN0); /*! SCK */
GPIO_SetFunc(GPIOB, GPIO_PIN3, GPIO_FUN0); /*! MOSI */
GPIO_SetDir(GPIOB, GPIO_PIN5, GPIO_OUT);
GPIO_SetDir(GPIOB, GPIO_PIN3, GPIO_OUT);
GPIO_SetPinLevel(GPIOB, GPIO_PIN5, GPIO_LEVEL_HIGH);
#else
SPI_ConfigType spiConfig; /*! SPI配置结构体*/
/*! 初始化SPI引脚,功能复用选择.*/
GPIO_SetFunc(GPIOB, GPIO_PIN5, GPIO_FUN3); /*! SCK */
GPIO_SetFunc(GPIOB, GPIO_PIN3, GPIO_FUN3); /*! MOSI */
/*! 清零配置结构体变量.*/
memset(&spiConfig, 0x00, sizeof(spiConfig));
/*! 初始化SPI参数,波特率 = 2Mbps = (F_BCLK / (SCK_LOW+1 + SCK_HIGH+1)).*/
spiConfig.sckHigh = 3; /*! SCK高电平时间 = (SCK_HIGH + 1) * CLK_PERIOD.*/
spiConfig.sckLow = 3; /*! SCK低电平时间 = (SCK_LOW + 1) * CLK_PERIOD.*/
spiConfig.mode = SPI_MASTER; /*! 设置为主机模式*/
spiConfig.cpha = SPI_CPHA_2EDGE; /*! 设置数据采样相位,第2个边沿采样数据*/
spiConfig.cpol = SPI_CPOL_HIGH; /*! 设置SCK空闲时极性,空闲时SCK为高*/
spiConfig.frmSize = SPI_FRAME_SIZE_8BITS;
spiConfig.rxMsbFirstEn = ENABLE; /*! 选择从最高位开始接收*/
spiConfig.txMsbFirstEn = ENABLE; /*! 选择从最高位开始发送*/
spiConfig.csOutputEn = DISABLE; /*! CS由SPI软件控制*/
spiConfig.continuousCSEn = ENABLE; /*! 片选连续模式*/
spiConfig.modeFaultEn = DISABLE; /*! 模式故障禁止*/
spiConfig.wakeUpEn = DISABLE; /*! 主机模式不支持唤醒功能*/
spiConfig.spiEn = ENABLE;
spiConfig.interruptEn = DISABLE; /*! 使能NVIC中断*/
spiConfig.txUFInterruptEn = DISABLE; /*! 打开TXUF中断,可禁止*/
spiConfig.rxOFInterruptEn = DISABLE; /*! 打开RXOF中断,可禁止*/
spiConfig.modeFaultInterruptEn = DISABLE; /*! 关闭模式故障中断*/
SPI_Init(SPI0, &spiConfig);
#endif
}
void yuyy_hs12864g18b_cs(uint8_t lev)
{
GPIO_SetPinLevel(GPIOA, GPIO_PIN7, (lev == 0 ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH));
}
void yuyy_hs12864g18b_rst(uint8_t lev)
{
GPIO_SetPinLevel(GPIOA, GPIO_PIN8, (lev == 0 ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH));
}
void yuyy_hs12864g18b_a0(uint8_t lev)
{
GPIO_SetPinLevel(GPIOA, GPIO_PIN9, (lev == 0 ? GPIO_LEVEL_LOW : GPIO_LEVEL_HIGH));
}
void yuyy_hs12864g18b_spiwritebyte(uint8_t dat)
{
#if(YUYY_USE_SOFT_SPI)
uint8_t i = 0;
while(i<8)
{
GPIO_SetPinLevel(GPIOB, GPIO_PIN5, GPIO_LEVEL_LOW);
if(dat & 0x80)
GPIO_SetPinLevel(GPIOB, GPIO_PIN3, GPIO_LEVEL_HIGH);
else
GPIO_SetPinLevel(GPIOB, GPIO_PIN3, GPIO_LEVEL_LOW);
GPIO_SetPinLevel(GPIOB, GPIO_PIN5, GPIO_LEVEL_HIGH);
dat <<= 1;
i++;
}
#else
SPI_TransmitPoll(SPI0, &dat,1);
#endif
}
void yuyy_hs12864g18b_delayus(uint16_t us)
{
udelay(us);
}
运行效果
3.7 I2C读取DHTC12
以前也用别的芯片驱动过,文件复制过来改一下I2C通讯部分就行了
移植修改的代码#include "ac780x_i2c.h"
#define DHTC12_IIC I2C0
#define DHTC12_I2C_ADDR 0x44
static uint16_t HumA,HumB;
void yuyy_dhtc12_iic_init(void)
{
I2C_ConfigType i2cConfig;
/*清零结构体变量.*/
memset(&i2cConfig, 0x00, sizeof(i2cConfig));
/*初始化引脚功能为I2C.*/
GPIO_SetFunc(GPIOB, GPIO_PIN7, GPIO_FUN3);
GPIO_SetFunc(GPIOB, GPIO_PIN8, GPIO_FUN3);
/*无论是主机还是从机模式都需要配置的参数.*/
i2cConfig.mode = I2C_MASTER; /*设置主机模式.*/
i2cConfig.extAddrEn = DISABLE; /*10bit扩展地址禁能.*/
i2cConfig.interruptEn = DISABLE; /*I2C中断,BND/SAMF/ARBLOST.*/
i2cConfig.nackInterruptEn = DISABLE; /*NACK中断.*/
i2cConfig.ssInterruptEn = DISABLE; /*总线start或stop中断.*/
i2cConfig.i2cEn = ENABLE; /*使能模块.*/
i2cConfig.callBack = NULL; /*中断回调函数.*/
/*主机模式需要配置的参数,配置成从机模式可忽略.*/
/*波特率设置
f = APB时钟/((sampleCnt+1)*(stepCnt+1)*2)
当APB时钟为16M,所需波特率为100Kbps
可配置半脉冲宽度stepCnt为7,每个采样点宽度sampleCnt为9
则波特率 = 16M/((9+1)*(7+1)*2) = 100K
*/
i2cConfig.masterConfig.sampleCnt = 119; /*设置波特率为100Kbps,bandrate=(16M/(10*8*2))=100Kbps.*/
i2cConfig.masterConfig.stepCnt = 117;
i2cConfig.masterConfig.ARBEn = DISABLE; /*设置主机仲裁功能.*/
i2cConfig.masterConfig.SYNCEn = DISABLE; /*设置主机SCL同步功能.*/
I2C_Init(DHTC12_IIC, &i2cConfig);
}
uint8_t yuyy_dhtc12_iic_senddatas(uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen,uint8_t *datas,uint8_t datalen)
{
uint8_t i = 0,status = I2C_HW_STATUS_ERROR_NULL;
uint8_t iicdatas[16] = {0};
if(regaddrlen == 1)
{
iicdatas[0] = regaddr&0xFF;
}
else if(regaddrlen == 2)
{
iicdatas[0] = (regaddr>>8)&0xFF;
iicdatas[1] = regaddr&0xFF;
}
i = regaddrlen;
while(i < regaddrlen+datalen)
{
iicdatas[i] = datas[i-regaddrlen];
i++;
}
status = I2C_MasterTransmitPoll(DHTC12_IIC,devaddr,iicdatas,regaddrlen+datalen,ENABLE);
return status;
}
uint8_t yuyy_dhtc12_iic_readdatas(uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen,uint8_t *datas,uint8_t datalen)
{
uint8_t status = I2C_HW_STATUS_ERROR_NULL;
uint8_t iicdatas[2] = {0};
if(regaddrlen > 0)
{
if(regaddrlen == 1)
{
iicdatas[0] = regaddr&0xFF;
}
else if(regaddrlen == 2)
{
iicdatas[0] = (regaddr>>8)&0xFF;
iicdatas[1] = regaddr&0xFF;
}
status = I2C_MasterTransmitPoll(DHTC12_IIC,devaddr,iicdatas,regaddrlen+datalen,DISABLE);
}
if(status == I2C_HW_STATUS_ERROR_NULL)
{
I2C_MasterReceivePoll(DHTC12_IIC,devaddr,datas,datalen);
}
return status;
}
void yuyy_dhtc12_delayms(uint16_t ms)
{
mdelay(ms);
}
运行效果
4.恒温恒湿控制箱模拟实现
综合上面的实验例程,利用开发板资源模拟实现一个恒温恒湿控制箱,使用I2C读取DHTC12测量温湿度,使用2个LED分别表示温度 湿度是否达标,达标则熄灭,不达标则亮起以1秒为周期闪烁,加湿加热时0.5秒内亮两次后0.5秒保持熄灭,除湿降温时0.5秒亮起0.5秒熄灭,通过LCD屏幕显示当前温湿度和升温/降温 加湿/除湿状态,长按按键进入设定模式,旋转电位器调节数值(电位器不能无限旋转所以做不了相对值调节,本来应该用按键或者编码器的)由于没有温度调节和湿度调节装置,因此只能做个简单的模拟,程序里还会有其它问题,包括但不限于:所有操作都放在了一个定时器里没有区分优先级,设置数值立即生效没有做保存与否的功能,没有温湿度的设置值是否合理的检测,鉴于这只是个简单的模拟所以请忽略
部分代码实现
#define THREFRESHTIMME 200 //2秒
#define BOX_T_OFFSET 5 //温度误差范围
#define BOX_H_OFFSET 5 //湿度误差范围
#define BOX_KEY_LONGPRESSTIME 100//1秒
/* =========================================== Typedef ============================================ */
typedef enum
{
THState_Normal = 0, //温湿度正常
THState_High, //温湿度高
THState_Low //温湿度低
} THState_t;
typedef enum
{
THWorkingState_Stop = 0, //温湿度控制器不工作
THWorkingState_Up, //温湿度控制器加湿/升温中
THWorkingState_Down //温湿度控制器除湿/降温中
} THWorkingState_t;
/* ========================================== Variables =========================================== */
uint8_t g_rxLen = 0; /*!< 串口接收长度变量 */
uint8_t g_txLen = 0; /*!< 串口发送长度变量 */
uint8_t g_txCnt = 0;
uint8_t g_rxBuf[RX_BUF_LEN] = {0}; /*!< 串口接收数组 */
uint8_t const test16x16dang[];/*"当",0*/
uint8_t const test16x16qian[];/*"前",1*/
uint8_t const test16x16mu[];/*"目",2*/
uint8_t const test16x16biao[];/*"标",3*/
uint8_t const test16x16jia[];/*"加",0*/
uint8_t const test16x16chu[];/*"除",1*/
uint8_t const test16x16shi[];/*"湿",2*/
uint8_t const test16x16sheng[];/*"升",3*/
uint8_t const test16x16jiang[];/*"降",4*/
uint8_t const test16x16wen[];/*"温",5*/
uint8_t const test16x16zhong[];/*"中",0*/
uint8_t const test16x16temp[];
uint8_t box_setting_mode = 0; //0正常工作 1设置温度 2设置湿度
int16_t box_target_temp = 250; //目标温度25.0
uint16_t box_target_humi = 500; //目标湿度50.0%
int16_t box_current_temp = 250; //目标温度25.0
uint16_t box_current_humi = 500; //目标湿度50.0%
uint32_t box_timer_count = THREFRESHTIMME;
THState_t box_temp_state;
THState_t box_humi_state;
THWorkingState_t box_temp_controller_state;
THWorkingState_t box_humi_controller_state;
uint16_t box_led_temp = 0;
uint16_t box_led_humi = 0;
uint8_t box_key_down_count = 0;
//初始化函数省略
void box_adc_init();
void box_ledinit();
void box_timer_init();
void box_keyinit();
//
void box_refresh_display()
{
char out[15];
uint8_t outlen,col;
yuyy_hs12864g18b_display_graphic_16x16(0,0,0,(uint8_t *)test16x16dang);
yuyy_hs12864g18b_display_graphic_16x16(0,0,16,(uint8_t *)test16x16qian);
memset(out,0,15);
outlen = sprintf(out,"%.1f%% %.1f",box_current_humi/10.0,box_current_temp/10.0);
yuyy_hs12864g18b_display_string_8x16(0,0,32,(uint8_t *)out);
col = 32+8*outlen;
yuyy_hs12864g18b_display_graphic_16x16(0,0,col,(uint8_t *)test16x16temp);
yuyy_hs12864g18b_display_graphic_16x16(0,2,0,(uint8_t *)test16x16mu);
yuyy_hs12864g18b_display_graphic_16x16(0,2,16,(uint8_t *)test16x16biao);
memset(out,0,15);
outlen = sprintf(out,"%.1f%%",box_target_humi/10.0);
yuyy_hs12864g18b_display_string_8x16(box_setting_mode==2?1:0,2,32,(uint8_t *)out);
yuyy_hs12864g18b_display_string_8x16(0,2,32+outlen*8,(uint8_t *)" ");
outlen += 1;
col = 32+8*outlen;
outlen = sprintf(out,"%.1f",box_target_temp/10.0);
yuyy_hs12864g18b_display_string_8x16(box_setting_mode==1?1:0,2,col,(uint8_t *)out);
col += 8*outlen;
yuyy_hs12864g18b_display_graphic_16x16(0,2,col,(uint8_t *)test16x16temp);
yuyy_hs12864g18b_display_string_8x16(0,2,col+16,(uint8_t *)" ");
col = 0;
if(box_humi_controller_state != THWorkingState_Stop)
{
yuyy_hs12864g18b_display_graphic_16x16(0,4,0,(uint8_t *)(box_humi_controller_state==THWorkingState_Up?test16x16jia:test16x16chu));
yuyy_hs12864g18b_display_graphic_16x16(0,4,16,(uint8_t *)test16x16shi);
yuyy_hs12864g18b_display_graphic_16x16(0,4,32,(uint8_t *)test16x16zhong);
col = 48;
}
if(col > 0)
{
yuyy_hs12864g18b_display_string_8x16(0,4,col,(uint8_t *)" ");
col = 64;
}
if(box_temp_controller_state != THWorkingState_Stop)
{
yuyy_hs12864g18b_display_graphic_16x16(0,4,col,(uint8_t *)(box_temp_controller_state==THWorkingState_Up?test16x16sheng:test16x16jiang));
yuyy_hs12864g18b_display_graphic_16x16(0,4,col+16,(uint8_t *)test16x16wen);
yuyy_hs12864g18b_display_graphic_16x16(0,4,col+32,(uint8_t *)test16x16zhong);
col += 48;
}
yuyy_hs12864g18b_display_string_8x16(0,4,col,(uint8_t *)" ");
yuyy_hs12864g18b_display_string_8x16(0,6,0,(uint8_t *)"Code by yuyy1989");
}
void box_get_th()
{
yuyy_dhtc12_readHT(&box_current_temp,&box_current_humi);
if(box_current_temp < box_target_temp - BOX_H_OFFSET)
{
box_temp_state = THState_Low;
}
else if(box_current_temp > box_target_temp + BOX_H_OFFSET)
{
box_temp_state = THState_High;
}
else
{
box_temp_state = THState_Normal;
}
if(box_current_humi < box_target_humi - BOX_H_OFFSET)
{
box_humi_state = THState_Low;
}
else if(box_current_humi > box_target_humi + BOX_H_OFFSET)
{
box_humi_state = THState_High;
}
else
{
box_humi_state = THState_Normal;
}
}
void box_set_THcontroller(void)
{
if(box_temp_state == THState_High)
{
//温度高该降温
if(box_temp_controller_state != THWorkingState_Down)
{
box_temp_controller_state = THWorkingState_Down;
}
}
else if(box_temp_state == THState_Low)
{
//温度低该升温
if(box_temp_controller_state != THWorkingState_Up)
{
box_temp_controller_state = THWorkingState_Up;
}
}
else
{
//温度符合要求停止升降温
if(box_temp_controller_state != THWorkingState_Stop)
{
box_temp_controller_state = THWorkingState_Stop;
}
}
if(box_humi_state == THState_High)
{
//湿度高该除湿
if(box_humi_controller_state != THWorkingState_Down)
{
box_humi_controller_state = THWorkingState_Down;
}
}
else if(box_humi_state == THState_Low)
{
//湿度低该加湿
if(box_humi_controller_state != THWorkingState_Up)
{
box_humi_controller_state = THWorkingState_Up;
}
}
else
{
//湿度符合要求停止除湿加湿
if(box_humi_controller_state != THWorkingState_Stop)
{
box_humi_controller_state = THWorkingState_Stop;
}
}
}
void box_prockey(void)
{
if(GPIO_GetPinLevel(KEYPORT, KEYPIN) == GPIO_LEVEL_LOW)
{
if(box_key_down_count<0xFF)
box_key_down_count += 1;
if(box_key_down_count == BOX_KEY_LONGPRESSTIME)
{
if(box_setting_mode == 0)
{
box_setting_mode = 1;
box_refresh_display();
}
else
{
box_setting_mode = 0;
box_timer_count = 0;
}
}
}
else
{
if(box_key_down_count > 3 && box_key_down_count < BOX_KEY_LONGPRESSTIME)
{
if(box_setting_mode == 1)
{
box_setting_mode = 2;
}
else
{
box_setting_mode = 1;
}
box_refresh_display();
}
box_key_down_count = 0;
}
}
void box_THcontroller_run(void) //LED模拟工作状态
{
if(box_led_temp < 100)
{
box_led_temp += 1;
}
else
{
box_led_temp = 0;
}
if(box_temp_controller_state == THWorkingState_Down)
{
box_setled1onoff(box_led_temp<50?1:0);
}
else if(box_temp_controller_state == THWorkingState_Up)
{
box_setled1onoff((box_led_temp<15||(box_led_temp>=30&&box_led_temp<45
))?1:0);
}
else
{
box_setled1onoff(0);
}
if(box_led_humi < 100)
{
box_led_humi += 1;
}
else
{
box_led_humi = 0;
}
if(box_humi_controller_state == THWorkingState_Down)
{
box_setled2onoff(box_led_humi<50?1:0);
}
else if(box_humi_controller_state == THWorkingState_Up)
{
box_setled2onoff((box_led_humi<20||(box_led_humi>=40&&box_led_humi<60))?1:0);
}
else
{
box_setled2onoff(0);
}
}
void box_timer_cb(void *device, uint32_t wpara, uint32_t lpara)
{
box_prockey();
if(box_timer_count > 0)
{
box_timer_count -= 1;
}
else
{
box_timer_count = THREFRESHTIMME;
box_get_th();
box_set_THcontroller();
box_refresh_display();
}
if(box_setting_mode == 1)
{
box_target_temp = 1000 - box_getadc()/4095.0 * 1000;
box_refresh_display();
}
else if(box_setting_mode == 2)
{
box_target_humi = 1000 - box_getadc()/4095.0 * 1000;
box_refresh_display();
}
box_THcontroller_run();
}
int main(void)
{
InitDelay();
box_adc_init();
box_ledinit();
box_timer_init();
box_keyinit();
yuyy_dhtc12_init();
yuyy_hs12864g18b_init();
yuyy_hs12864g18b_clear_screen();
while (1)
{
}
}
运行效果
设置目标温湿度
LED指示工作状态,除湿升温状态
|