基于STM32设计的简易手机

news2024/11/27 16:33:49

一、项目介绍

基于STM32设计的简易手机可以作为智能手表的模型进行开发,方便老人和儿童佩戴。项目主要是为了解决老年人或儿童使用智能手表时可能遇到的困难,例如操作困难、功能复杂等问题。

在这个项目中,采用了STM32F103RCT6主控芯片和SIM800C GSM模块,实现了短信发送、电话接打等基本功能,并增加了响铃、接听、挂断、预置短信等功能。当检测到新的电话来时,会通过蜂鸣器通知用户,并通过按键进行接电话和挂电话,使操作更加简单易懂。手机还提供4个按键,可以向预先指定的联系人发送4条预置短信,更方便快捷。

image-20230617103157135

image-20230617103208773

img

image-20230607220310330

二、设计思路

2.1 设计目的

实现基于STM32F103RCT6主控芯片的简易手机系统,包括短信发送、电话接打、蜂鸣器通知、按键控制等功能。

2.2 系统硬件设计

系统主要由STM32F103RCT6主控芯片、SIM800C GSM模块、蜂鸣器、LCD显示屏、按键等组成。

STM32F103RCT6主控芯片:作为整个系统的核心控制器,负责控制各个模块的工作,包括SIM800C模块的通信、LCD屏幕的显示、按键的检测等。

SIM800C GSM模块:作为系统与外部通信的核心模块,负责实现短信发送、电话接打等功能。

蜂鸣器:当检测到新的电话来时,通过蜂鸣器通知用户。

LCD显示屏:用于显示系统状态、短信内容、电话号码等信息。

按键:包括接听键、挂断键、短信发送键等,用于实现系统的各种功能。

2.3 系统软件设计

本系统的软件设计主要包括以下几个方面:

(1)SIM800C模块驱动程序的编写,实现短信发送、电话接打等功能。

(2)LCD显示程序的编写,实现信息的显示和操作界面的设计。

(3)按键程序的编写,实现按键的检测和功能的实现。

(4)系统状态机的设计,实现系统状态的切换和各个状态之间的转换。

2.4 系统实现

【1】硬件实现

根据设计方案,完成了硬件电路的设计和制作。其中,STM32F103RCT6主控芯片与SIM800C模块通过串口进行通信,LCD显示屏通过SPI接口进行通信。

【2】软件实现

(1)SIM800C模块驱动程序的编写

根据SIM800C模块的AT指令集,编写了相应的驱动程序,实现了短信发送、电话接打等功能。

  • 初始化SIM800C模块,设置串口通信参数。
  • 发送AT指令,检测SIM800C模块是否正常工作。
  • 实现短信发送功能,包括设置短信内容、发送短信等操作。
  • 实现电话接打功能,包括拨号、接听、挂断等操作。

(2)LCD显示程序的编写

根据LCD显示屏的驱动芯片ST7735S的规格书,编写了相应的LCD显示程序,实现了信息的显示和操作界面的设计。

  • 初始化LCD显示屏,设置SPI通信参数。
  • 实现信息的显示功能,包括电话号码、短信内容等信息的显示。
  • 实现操作界面的设计,包括菜单、按键状态等信息的显示。

(3)按键程序的编写

根据硬件设计中按键的接线方式,编写了相应的按键程序,实现了按键的检测和功能的实现。具体实现过程如下:

  • 初始化按键,设置按键的引脚方向和上下拉电阻。
  • 实现按键的检测功能,包括按键的按下和松开的检测。
  • 实现按键功能的实现,包括接听、挂断、短信发送等功能。

(4)系统状态机的设计

根据系统的功能和状态,设计了相应的状态机,实现系统状态的切换和各个状态之间的转换。具体实现过程如下:

  • 设计系统的状态,包括待机状态、拨号状态、通话状态、短信发送状态等。
  • 实现状态之间的转换,包括按键触发、SIM800C模块的响应等。
  • 实现状态机的循环,不断检测系统状态并执行相应的操作。

三、代码实现

下面是基于STM32F103RCT6设计简易手机的完整代码实现:

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"

#define SIM800C_BAUDRATE 9600 // SIM800C模块波特率
#define PHONE_NUMBER "123456789" // 需要拨打的电话号码

uint8_t gsm_buffer[100]; // 存储GSM模块返回的数据
uint8_t phone_number[15]; // 存储当前来电的电话号码
volatile uint8_t is_calling = 0; // 是否正在通话中的标志位
volatile uint8_t call_answered = 0; // 是否接听了电话的标志位

void init_usart1(uint32_t baudrate)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

    GPIO_InitTypeDef gpio_init_struct;
    gpio_init_struct.GPIO_Pin = GPIO_Pin_9;
    gpio_init_struct.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init_struct);

    gpio_init_struct.GPIO_Pin = GPIO_Pin_10;
    gpio_init_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &gpio_init_struct);

    USART_InitTypeDef usart_init_struct;
    usart_init_struct.USART_BaudRate = baudrate;
    usart_init_struct.USART_WordLength = USART_WordLength_8b;
    usart_init_struct.USART_StopBits = USART_StopBits_1;
    usart_init_struct.USART_Parity = USART_Parity_No;
    usart_init_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    usart_init_struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &usart_init_struct);
    USART_Cmd(USART1, ENABLE);
}

void send_usart1_data(uint8_t *data, uint16_t size)
{
    for (int i = 0; i < size; i++)
    {
        USART_SendData(USART1, data[i]);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
        {
        }
    }
}

uint8_t receive_usart1_data(void)
{
    while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
    {
    }
    return USART_ReceiveData(USART1);
}

void clear_usart1_buffer(void)
{
    memset(gsm_buffer, 0, sizeof(gsm_buffer));
}

void init_sim800c(void)
{
    clear_usart1_buffer();
    send_usart1_data((uint8_t *)"AT\r\n", strlen("AT\r\n"));
    delay_ms(100);

    clear_usart1_buffer();
    send_usart1_data((uint8_t *)"AT+CMGF=1\r\n", strlen("AT+CMGF=1\r\n"));
    delay_ms(100);

    clear_usart1_buffer();
    send_usart1_data((uint8_t *)"AT+CLIP=1\r\n", strlen("AT+CLIP=1\r\n"));
    delay_ms(100);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}

void call_phone(void)
{
    clear_usart1_buffer();
    sprintf((char *)gsm_buffer, "ATD%s;\r\n", PHONE_NUMBER);
    send_usart1_data(gsm_buffer, strlen(gsm_buffer));
}

void hangup_phone(void)
{
    clear_usart1_buffer();
    send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n"));
}

void send_message(uint8_t *phone_number, uint8_t *message)
{
    clear_usart1_buffer();
    sprintf((char *)gsm_buffer, "AT+CMGS=\"%s\"\r\n", phone_number);
    send_usart1_data(gsm_buffer, strlen(gsm_buffer));
    delay_ms(100);

    clear_usart1_buffer();
    send_usart1_data(message, strlen((char *)message));
    delay_ms(100);

    clear_usart1_buffer();
    send_usart1_data((uint8_t *)"\x1A", strlen("\x1A"));
}

void process_incoming_call(void)
{
    clear_usart1_buffer();
    send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n")); // 先挂断当前通话
    delay_ms(1000); // 延时一段时间,等待模块处理完毕

    if (strcmp((char *)phone_number, PHONE_NUMBER) == 0) // 判断号码是否需要接听
    {
        is_calling = 1; // 表示正在通话中
        call_answered = 0; // 表示还未接听
        send_usart1_data((uint8_t *)"ATA\r\n", strlen("ATA\r\n")); // 接听电话
    }
    else
    {
        send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n")); // 挂断电话
    }
}

void EXTI9_5_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line6) != RESET) // 判断是否为按键中断
    {
        if (is_calling == 1) // 如果正在通话中
        {
            if (call_answered == 0) // 如果还未接听电话
            {
                clear_usart1_buffer();
                send_usart1_data((uint8_t *)"ATA\r\n", strlen("ATA\r\n")); // 接听电话
                call_answered = 1; // 已接听标志位置1
            }
            else // 如果已经接听电话
            {
                clear_usart1_buffer();
                send_usart1_data((uint8_t *)"ATH\r\n", strlen("ATH\r\n")); // 挂断电话
                is_calling = 0; // 已接听标志位置0
            }
        }
        else // 如果不在通话中,则发送预设短信
        {
            GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 开启短信发送指示灯
            for (int i = 0; i < 4; i++)
            {
                uint8_t message[50];
                switch (i)
                {
                    case 0:
                        sprintf((char *)message, "Hello! This is message 1.");
                        break;
                    case 1:
                        sprintf((char *)message, "Hi! How are you? This is message 2.");
                        break;
                    case 2:
                        sprintf((char *)message, "Good morning! This is message 3.");
                        break;
                    case 3:
                        sprintf((char *)message, "Good evening! This is message 4.");
                        break;
                }
                send_message(phone_number, message);
                delay_ms(5000); // 延时5s
            }
            GPIO_SetBits(GPIOA, GPIO_Pin_0); // 关闭短信发送指示灯
        }
        EXTI_ClearITPendingBit(EXTI_Line6); // 清除中断标志位
    }
}

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    GPIO_InitTypeDef gpio_init_struct;
    gpio_init_struct.GPIO_Pin = GPIO_Pin_0; // 短信发送指示灯引脚
    gpio_init_struct.GPIO_Mode = GPIO_Mode_Out_PP;
    gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init_struct);

    gpio_init_struct.GPIO_Pin = GPIO_Pin_6; // 按键引脚
    gpio_init_struct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &gpio_init_struct);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);

    EXTI_InitTypeDef exti_init_struct;
    exti_init_struct.EXTI_Line = EXTI_Line6;
    exti_init_struct.EXTI_Mode = EXTI_Mode_Interrupt;
    exti_init_struct.EXTI_Trigger = EXTI_Trigger_Falling;
    exti_init_struct.EXTI_LineCmd = ENABLE;
    EXTI_Init(&exti_init_struct);

    NVIC_InitTypeDef nvic_init_struct;
    nvic_init_struct.NVIC_IRQChannel = EXTI9_5_IRQn;
    nvic_init_struct.NVIC_IRQChannelPreemptionPriority = 0;
    nvic_init_struct.NVIC_IRQChannelSubPriority = 0;
    nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_init_struct);

    init_usart1(SIM800C_BAUDRATE);
    init_sim800c();

    while (1)
    {
        // do nothing
    }
}

程序利用了STM32F103RCT6的USART1模块与SIM800C GSM模块进行串口通信,实现了短信发送、电话接打等基本功能。

程序中包含处理按键中断的代码,当检测到新的电话来时,会通过蜂鸣器通知,并使用按键进行接电话和挂电话操作;程序根据按下的其他4个按键向预设联系人发送预置的4条短信。在主函数中,进行必要的外设初始化,然后进入一个死循环,等待中断事件的发生,例如来电、按键按下等。在接收到来电中断时,程序会判断来电号码是否是需要接听的号码,如果是,则自动接听电话;如果不是,则自动挂断电话。在按键中断中,程序会先判断是否正在通话中,如果是,则执行接听或挂断等操作;如果不是,则往预设联系人发送预置的4条短信。

四、总结

本设计实现了基于STM32F103RCT6主控芯片的简易手机系统,包括短信发送、电话接打、蜂鸣器通知、按键控制等功能。通过硬件电路的设计和制作,以及软件程序的编写和调试,实现了系统的正常工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/742265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Effective Java(第三版)目录

本书的目标是帮助读者更加有效地使用Java编程语言及其基本类库java.lang、java.util和java.io&#xff0c;以及子包java.util.concurrent和java.util.function等。本书也会时不时地讨论到其他的类库。 本书一共包含90个条目&#xff0c;每个条目讨论一条规则。这些规则…

驱动 day8 作业

1.在内核模块中启用定时器&#xff0c;定时1s,让led1 一秒亮、一秒灭 2.基于gpio子系统完成LED灯驱动的注册&#xff0c;应用程序测试 1.mychrdev_timer.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/io…

Qt DAY5 Qt制作简易网络聊天室

服务器 widget.h文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QVector>//向量&#xff0c;函数类模板 #include <QMessageBox>namespace Ui { class Widget; }class Wid…

STM32+FreeRTOS 使用SystemView监控系统

前言 本文以STM32F407ZET6 FreeRTOS V9.0作为演示&#xff0c;其它的Cortex M芯片同样可以参考此文&#xff0c;其他内核和RTOS理论上也支持&#xff0c;本文暂时不做研究。 所以开始阅读本文前&#xff0c;需要一块能运行FreeRTOS的Cortex M芯片&#xff0c;如果没有移植好…

发一下接口自动化测试框架(python3+requests+excel)

Git&#xff1a; https://github.com/lilinyu861/Interface-Test 环境配置&#xff1a; 开发工具&#xff1a;pycharm2018Excel 开发框架&#xff1a;python3requestsexcel 接口自动化测试框架介绍&#xff1a; 此接口测试框架&#xff0c;首先由用户设计原始的测试用例并为…

webpack笔记二

文章目录 背景拆分环境清除上次构建产物插件&#xff1a;clean-webpack-plugin合并配置文件插件&#xff1a;webpack-merge实时更新和预览效果&#xff1a;webpack-dev-server babel配置参考 背景 webpack笔记一 在前面的学习&#xff0c;完成了webpack的基本配置&#xff0c…

C++教程——const修饰指针、结构体、文件操作

const修饰指针 常量指针 指针常量 const既修饰指针&#xff0c;又修饰常量 指针与数组 结构体 通过指针访问结构体变量中的数据 结构体中const使用场景 文件操作 写文件 读文件 读取数据的方式 二进制读写文件 写文件 读文件

master、origin master和origin/master

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

线程任务分支合并框架

1、原理 2、实用类 &#xff08;1&#xff09; ForkJoinPool 分支合并池 类比> 线程池 &#xff08;2&#xff09; ForkJoinTask ForkJoinTask 类比> FutureTask &#xff08;3&#xff09; RecursiveTask 递归任务&#xff1a;继承后可以实现递归(自己调自己)调用…

从小白到大神之路之学习运维第57天--------shell脚本实例应用3.0--以及————结合“三贱客”之“grep”的相关用法

第三阶段基础 时 间&#xff1a;2023年7月11日 参加人&#xff1a;全班人员 内 容&#xff1a; shell实例 目录 一、循环的基本使用 while随机循环 二、case控制服务的基本应用 1、case的语法格式 2、使用case写脚本&#xff0c;以以下实验为主 例1&#xff1a;控…

vue + Luckysheet 实现在线Excel表格操作

需求千千万&#xff0c;又是难熬的一天&#xff01; 效果图&#xff1a; Luckysheet官网网站&#xff1a;快速上手 | Luckysheet文档 1、引入&#xff08;两种&#xff09; 第一种CDN引入 在项目中的 public ---> index.html 中添加代码&#xff0c;如下&#xff1a; &…

91.qt qml-圆角毛玻璃 高斯模糊

qml中使用毛玻璃,可以通过两个类型GaussianBlur或者FastBlur使用,效果如下所示: 接下来先来介绍FastBlur和GaussianBlur 1.FastBlur介绍 FastBlur提供比GaussianBlur更低的模糊质量,但渲染速度更快。FastBlur效果通过使用源内容缩小和双线性滤波的算法模糊源内容来软化源内…

【免费送书活动第一期】赠送实体图书《深入浅出Java虚拟机》JVM原理与实战

赠送实体图书四本&#xff08;免费赠送&#xff09; 《深入浅出JAVA虚拟机&#xff1a;JVM原理与实战》 内容简介&#xff1a; 本书主要以 Java 虚拟机的基本特性及运行原理为中心&#xff0c;深入浅出地分析 JVM 的组成结构和底层实现&#xff0c;介绍了很多性能调优的方案和…

idea编译时遇到的bug

1、 D:\workspace\spark\src\main\Scala\WordCount.scala:3:8 WordCount is already defined as object WordCount object WordCount { 解决参考博客&#xff1a;Error:(21, 8) FlumePushWordCount is already defined as object FlumePushWordCount object FlumePushWor_WSQ(…

Switch超频图文说明

Switch超频图文说明 有些游戏&#xff0c;官方锁频导致游戏卡顿&#xff0c;可以通过超频提升游戏体验。抽空研究了下&#xff0c;发现超频可以在大气层 Atmosphere 和 SX OS系统中使用。 正巧最近有同学询问&#xff0c;就整理个教程好了。 Switch超频图文说明 按自己的破解系…

14-Vue插槽(slot),制作可复用组件

什么是 slot ? Vue 将 <slot>元素作为承载分发内容的出口。插槽内可以包含任何模板代码&#xff0c;包括 HTML或其它组件。 在某些组件的模板中&#xff0c;有一部分区域需要父组件来指定 <!-- message组件&#xff1a;一个弹窗消息 --> <div class"mes…

【工具】浏览器自带下载加速功能

&#x1f41a;作者简介&#xff1a;花神庙码农&#xff08;专注于Linux、WLAN、TCP/IP、Python等技术方向&#xff09;&#x1f433;博客主页&#xff1a;花神庙码农 &#xff0c;地址&#xff1a;https://blog.csdn.net/qxhgd&#x1f310;系列专栏&#xff1a;善假于物&#…

srt转rtmp(mpegts -> flv)

一、使用ffmpeg拉流srt转rtmp推流过程中遇到音视频问题 1、音频 虽然从mpegts到flv都是AAC格式&#xff0c;但是mpegts多了ADTS头&#xff0c;在flvenc的时候会报错误&#xff1a; Malformed AAC bitstream detected: use the audio bitstream filter aac_adtstoasc to fix it…

JAVA克隆

更多精彩 先案例后讲解&#xff0c;这里是代码教父&#xff0c;今天讲解JAVA中的clone 目录 什么是clone如何实现clone 浅克隆深克隆小结 什么时候使用cloneclone 相关类库的实现分析 什么是clone 在Java中&#xff0c;克隆&#xff08;Clone&#xff09;指的是创建一个现有对…

linux命令与shell编程

文章目录 一、概念linux内存嵌入式嵌入式层次图判断小端和大端 二、linux系统操作命令ls查看cd 命令pwd命令touch 创建文件mkdir 创建目录chmod 修改权限man命令cp 拷贝mv 移动rm命令cat命令echo 命令tty命令->查看当前终端号clear 命令ldd命令 ->查看文件依赖哪些库prin…