各位朋友大家好,本期视频是基于美信MAX32660小封装微控制器的简易手表原型开发。
视频包括微控制器及其评估板的简要介绍, MAX32660 SPI、实时时钟、定时器及GPIO外部中断的应用,视频末尾有作品展示环节。还包含DHT11传感器的部分内容,此外ST3375串口屏的驱动程序和右上角图中的彩色数字方案也会分享给大家。
官方开发环境是典型的Eclipse搭配CDT插件形式, IDE自带一套例程,但是需要手动从安装目录加载,详细操作步骤已在视频中给出。
本期视频使用SPI驱动串口屏,Chili工具是本人维护的个人仓库,部分工具后续也会逐步开放给大家。软件工程参考了官方的应用示例,完整代码见工程文件。
ST7735串口屏的驱动请见工程代码。需要适配的部分粘贴如下。
main.c中:
/*与ST7735有关的宏定义*/
#define LCD_RST_PORT PORT_0
#define LCD_RST_PIN PIN_9
#define LCD_CS_PORT PORT_0
#define LCD_CS_PIN PIN_8
#define LCD_DC_PORT PORT_0
#define LCD_DC_PIN PIN_13
#define SPI SPI0A
#define SPI_SPEED 6000000
chilix7735.c中
/*以下定义需用户实现************************/
#define SPI SPI0A
#define LCD_CS_CLR GPIO_OutClr(&led_cs);
#define LCD_CS_SET GPIO_OutSet(&led_cs);
#define LCD_DC_CLR GPIO_OutClr(&led_dc);
#define LCD_DC_SET GPIO_OutSet(&led_dc);
#define LCD_RST_CLR GPIO_OutClr(&led_rst);
#define LCD_RST_SET GPIO_OutSet(&led_rst);
/*SPI发送函数************************************/
void SPI_Write_Data_x8(uint8_t Data)
{
//发送单个字节,请实现该函数
spi_req_t req;
req.tx_data = &Data;
req.rx_data = NULL;
req.len = 1;
req.bits = 8;
req.width = SPI17Y_WIDTH_1;
req.ssel = 0;
req.deass = 0;
req.tx_num = 0;
req.rx_num = 0;
req.callback = NULL;
SPI_MasterTrans(SPI, &req);
}
使用实时时钟时,需注意初始化RTC和启动RTC是通过调用不同函数来实现的。
/*与RTC有关的宏定义*/
#define SECS_PER_MIN 60
#define SECS_PER_HR (60 * SECS_PER_MIN)
#define SECS_PER_DAY (24 * SECS_PER_HR)
//初始化RTC
sys_cfg.tmr = MXC_TMR0;
if (RTC_Init(MXC_RTC, 33842, 0, &sys_cfg) != E_NO_ERROR)
{
printf("RTC_Init Error.\n");
return -1;
}
//启动RTC
if (RTC_EnableRTCE(MXC_RTC) != E_NO_ERROR)
{
printf("Failed RTC_EnableRTCE().\n");
return -1;
}
/*获取时间*/
void Get_Time(void)
{
sec = RTC_GetSecond();
day = sec / SECS_PER_DAY;
sec -= day * SECS_PER_DAY;
hr = sec / SECS_PER_HR;
sec -= hr * SECS_PER_HR;
min = sec / SECS_PER_MIN;
sec -= min * SECS_PER_MIN;
}
使用定时器读取传感器数据时,通过触发外部中断,并在中断内读取定时器计数的形式接收单个bit的数据。
/*设置定时器*/
void Set_Timer(void)
{
tmr_cfg_t tmr;
TMR_Disable(MXC_TMR1);
TMR_Init(MXC_TMR1, TMR_PRES_16, 0);
tmr.mode = TMR_MODE_CONTINUOUS;
tmr.cmp_cnt = 0;
tmr.pol = 0;
TMR_Config(MXC_TMR1, &tmr);
printf("Timer started.\n");
}
/*DHT11中断服务程序*/
void DHT11_ISR(void *cbdata)
{
uint8_t data_byte = 0;
TMR_Disable(MXC_TMR1);
tmr_cnt_us[tmr_cnt_times] = TMR_GetCount(MXC_TMR1) / 3;
TMR_SetCount(MXC_TMR1, 0);
tmr_cnt_times = tmr_cnt_times + 1;
if (tmr_cnt_times == 42)
{
tmr_cnt_times = 0;
for (uint8_t i = 0; i < 5; i++)
{
data_byte = 0;
for (uint8_t j = 0; j < 8; j++)
{
data_byte = (data_byte << 1) | (tmr_cnt_us[i * 8 + j + 2] > 90 ? 1 : 0);
}
sensor_data[i] = data_byte;
if (sensor_data[0] + sensor_data[1] + sensor_data[2] + sensor_data[3] == sensor_data[4])
{
humidity = sensor_data[0];
temperature = sensor_data[2];
}
}
}
else
TMR_Enable(MXC_TMR1);
}
通讯开始时,主机将总线拉低然后释放。这里拉低的时间有明确的要求,应在18~30ms内,才可被传感器判定为有效起始信号。此处使用的时间间隔是22ms。传感器接收到起始信号后会产生一个响应信号。传感器先将总线拉低83us,再释放总线。从总线被释放,至数据开始输出,这个时间是87us。所以整个响应是170us。第三步将输出传感器数据。数据有5个字节,以连续40个bit的形式发送。如果输出54us低电平,24us高电平,则该bit为0;如果输出54us低电平,71us高电平,则该bit为1。数据传输完成后,传感器继续将引脚拉低54us,随后释放总线。完成通信。
/*设置 DHT11 IO 为输出模式*/
void DHT11_Output(void)
{
gpio_cfg_t gpio_dht11;
gpio_dht11.port = DHT11_IO_PORT;
gpio_dht11.mask = DHT11_IO_PIN;
gpio_dht11.pad = GPIO_PAD_NONE;
gpio_dht11.func = GPIO_FUNC_OUT;
GPIO_Config(&gpio_dht11);
GPIO_IntDisable(&gpio_dht11);
NVIC_DisableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(DHT11_IO_PORT));
}
/*设置 DHT11 IO 为输入模式,并使能中断*/
void DHT11_Interrupt(void)
{
gpio_cfg_t gpio_dht11;
gpio_dht11.port = DHT11_IO_PORT;
gpio_dht11.mask = DHT11_IO_PIN;
gpio_dht11.pad = GPIO_PAD_NONE;
gpio_dht11.func = GPIO_FUNC_IN;
GPIO_Config(&gpio_dht11);
GPIO_RegisterCallback(&gpio_dht11, DHT11_ISR, &gpio_dht11);
GPIO_IntConfig(&gpio_dht11, GPIO_INT_EDGE, GPIO_INT_FALLING);
GPIO_IntEnable(&gpio_dht11);
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(DHT11_IO_PORT));
}
更多详细内容请直接查看工程代码文件。