<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>C语言表达式全解析:从基础语法到复杂工程场景</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
<!-- 引入语法高亮库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script>
// Tailwind 配置
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#E8F3FF',
accent: '#FF7D00',
dark: '#2D2D2D',
light: '#F9FAFB',
gray: {
100: '#F3F4F6',
200: '#E5E7EB',
300: '#D1D5DB',
400: '#9CA3AF',
500: '#6B7280',
600: '#4B5563',
700: '#374151',
800: '#1F2937',
900: '#111827'
}
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['Fira Code', 'Consolas', 'monospace']
},
boxShadow: {
'card': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
'hover': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)'
}
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.text-shadow {
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.transition-all-300 {
transition: all 300ms ease-in-out;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.code-block {
position: relative;
overflow-x: auto;
}
.copy-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
opacity: 0.7;
transition: opacity 0.3s;
}
.code-block:hover .copy-btn {
opacity: 1;
}
.nav-item-active {
@apply bg-primary/10 text-primary border-l-4 border-primary;
}
.table-responsive {
overflow-x: auto;
}
}
</style>
<script>
// 初始化语法高亮和复制功能
document.addEventListener('DOMContentLoaded', () => {
hljs.highlightAll();
// 复制代码功能
document.querySelectorAll('.copy-btn').forEach(btn => {
btn.addEventListener('click', () => {
const codeBlock = btn.parentElement.querySelector('code');
const text = codeBlock.textContent;
navigator.clipboard.writeText(text).then(() => {
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fa fa-check"></i> 已复制';
btn.classList.add('bg-green-500');
setTimeout(() => {
btn.innerHTML = originalText;
btn.classList.remove('bg-green-500');
}, 2000);
});
});
});
// 初始化运算符优先级图表
const initPriorityChart = () => {
const ctx = document.getElementById('priorityChart');
if (ctx) {
new Chart(ctx, {
type: 'bar',
data: {
labels: ['括号', '单目运算', '乘除模', '加减', '移位', '关系运算', '相等判断', '按位与', '按位异或', '按位或', '逻辑与', '逻辑或', '条件运算'],
datasets: [{
label: '运算符优先级',
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
backgroundColor: [
'rgba(22, 93, 255, 0.8)',
'rgba(22, 93, 255, 0.75)',
'rgba(22, 93, 255, 0.7)',
'rgba(22, 93, 255, 0.65)',
'rgba(22, 93, 255, 0.6)',
'rgba(22, 93, 255, 0.55)',
'rgba(22, 93, 255, 0.5)',
'rgba(22, 93, 255, 0.45)',
'rgba(22, 93, 255, 0.4)',
'rgba(22, 93, 255, 0.35)',
'rgba(22, 93, 255, 0.3)',
'rgba(22, 93, 255, 0.25)',
'rgba(22, 93, 255, 0.2)'
],
borderColor: [
'rgba(22, 93, 255, 1)'
],
borderWidth: 1
}]
},
options: {
indexAxis: 'y',
scales: {
x: {
beginAtZero: true,
max: 14,
title: {
display: true,
text: '优先级'
}
}
},
plugins: {
legend: {
position: 'top',
},
tooltip: {
callbacks: {
label: function(context) {
return `优先级: ${context.raw} (数值越小优先级越高)`;
}
}
}
},
maintainAspectRatio: false,
responsive: true
}
});
}
};
initPriorityChart();
// 移动端菜单切换
const menuToggle = document.getElementById('menu-toggle');
const mobileMenu = document.getElementById('mobile-menu');
if (menuToggle && mobileMenu) {
menuToggle.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden');
});
}
// 导航项激活状态
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
item.addEventListener('click', () => {
navItems.forEach(nav => nav.classList.remove('nav-item-active'));
item.classList.add('nav-item-active');
});
});
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
if (targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 80,
behavior: 'smooth'
});
// 在移动设备上点击导航后关闭菜单
if (window.innerWidth < 768) {
mobileMenu.classList.add('hidden');
}
}
});
});
// 监听滚动,高亮当前导航项
window.addEventListener('scroll', () => {
const sections = document.querySelectorAll('section[id]');
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
const sectionHeight = section.clientHeight;
if (pageYOffset >= (sectionTop - 100)) {
current = section.getAttribute('id');
}
});
navItems.forEach(item => {
item.classList.remove('nav-item-active');
if (item.getAttribute('data-target') === current) {
item.classList.add('nav-item-active');
}
});
});
});
</script>
</head>
<body class="bg-light font-sans text-gray-800">
<!-- 顶部导航栏 -->
<header class="fixed top-0 left-0 right-0 bg-white shadow-md z-50 transition-all duration-300">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fa fa-code text-primary text-2xl"></i>
<h1 class="text-xl md:text-2xl font-bold text-gray-800 hidden sm:block">C语言表达式解析</h1>
</div>
<!-- 移动端菜单按钮 -->
<button id="menu-toggle" class="md:hidden text-gray-700 focus:outline-none">
<i class="fa fa-bars text-xl"></i>
</button>
<!-- 桌面端导航 -->
<nav class="hidden md:flex space-x-6">
<a href="#intro" class="text-gray-700 hover:text-primary transition-colors">首页</a>
<a href="#basic" class="text-gray-700 hover:text-primary transition-colors">基础语法</a>
<a href="#hardware" class="text-gray-700 hover:text-primary transition-colors">硬件交互</a>
<a href="#communication" class="text-gray-700 hover:text-primary transition-colors">通信协议</a>
<a href="#advanced" class="text-gray-700 hover:text-primary transition-colors">高级应用</a>
</nav>
</div>
<!-- 移动端菜单 -->
<div id="mobile-menu" class="hidden md:hidden bg-white border-t border-gray-200">
<div class="container mx-auto px-4 py-2 flex flex-col space-y-3">
<a href="#intro" class="py-2 text-gray-700 hover:text-primary transition-colors">首页</a>
<a href="#basic" class="py-2 text-gray-700 hover:text-primary transition-colors">基础语法</a>
<a href="#hardware" class="py-2 text-gray-700 hover:text-primary transition-colors">硬件交互</a>
<a href="#communication" class="py-2 text-gray-700 hover:text-primary transition-colors">通信协议</a>
<a href="#advanced" class="py-2 text-gray-700 hover:text-primary transition-colors">高级应用</a>
</div>
</div>
</header>
<div class="container mx-auto px-4 pt-24 pb-16 flex flex-col md:flex-row">
<!-- 左侧导航栏 -->
<aside class="hidden md:block md:w-64 lg:w-72 flex-shrink-0 h-[calc(100vh-6rem)] sticky top-20 overflow-y-auto scrollbar-hide pr-4">
<nav class="bg-white rounded-lg shadow-card p-4">
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center">
<i class="fa fa-list-ul text-primary mr-2"></i>目录
</h2>
<ul class="space-y-1">
<li>
<a href="#intro" class="nav-item block px-3 py-2 rounded-md text-gray-700 hover:bg-gray-100 transition-colors" data-target="intro">
介绍
</a>
</li>
<li>
<a href="#basic" class="nav-item block px-3 py-2 rounded-md text-gray-700 hover:bg-gray-100 transition-colors" data-target="basic">
一、基础语法与表达式基础
</a>
<ul class="pl-4 mt-1 space-y-1">
<li>
<a href="#priority" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="priority">
1.1 运算符优先级与结合性
</a>
</li>
<li>
<a href="#evaluation" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="evaluation">
1.2 表达式求值顺序与副作用
</a>
</li>
<li>
<a href="#conversion" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="conversion">
1.3 类型转换与隐式转换规则
</a>
</li>
</ul>
</li>
<li>
<a href="#hardware" class="nav-item block px-3 py-2 rounded-md text-gray-700 hover:bg-gray-100 transition-colors" data-target="hardware">
二、硬件交互与嵌入式系统
</a>
<ul class="pl-4 mt-1 space-y-1">
<li>
<a href="#bit-operation" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="bit-operation">
2.1 寄存器位操作表达式
</a>
</li>
<li>
<a href="#bit-banding" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="bit-banding">
2.2 位带操作表达式
</a>
</li>
<li>
<a href="#dma" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="dma">
2.3 DMA配置与数据传输表达式
</a>
</li>
<li>
<a href="#interrupt" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="interrupt">
2.4 中断优先级管理表达式
</a>
</li>
</ul>
</li>
<li>
<a href="#communication" class="nav-item block px-3 py-2 rounded-md text-gray-700 hover:bg-gray-100 transition-colors" data-target="communication">三、通信协议与数据处理</a>
<ul class="pl-4 mt-1 space-y-1">
<li>
<a href="#uart" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="uart">
3.1 UART通信协议
</a>
</li>
<li>
<a href="#i2c" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="i2c">
3.2 I2C通信协议
</a>
</li>
<li>
<a href="#spi" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="spi">
3.3 SPI通信协议
</a>
</li>
<li>
<a href="#can" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="can">
3.4 CAN总线协议
</a>
</li>
</ul>
</li>
<li>
<a href="#advanced" class="nav-item block px-3 py-2 rounded-md text-gray-700 hover:bg-gray-100 transition-colors" data-target="advanced">四、高级应用与优化技巧</a>
<ul class="pl-4 mt-1 space-y-1">
<li>
<a href="#performance" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="performance">
4.1 表达式性能优化
</a>
</li>
<li>
<a href="#safety" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="safety">
4.2 安全关键系统中的表达式
</a>
</li>
<li>
<a href="#embedded" class="nav-item block px-3 py-1.5 rounded-md text-sm text-gray-600 hover:bg-gray-100 transition-colors" data-target="embedded">
4.3 嵌入式系统特定表达式
</a>
</li>
</ul>
</li>
</ul>
</nav>
</aside>
<!-- 主要内容区 -->
<main class="flex-1 md:ml-4 lg:ml-8">
<!-- 介绍部分 -->
<section id="intro" class="mb-12">
<div class="bg-white rounded-xl shadow-card p-6 md:p-8">
<div class="flex items-center mb-6">
<div class="w-12 h-12 rounded-full bg-primary/10 flex items-center justify-center mr-4">
<i class="fa fa-code text-primary text-2xl"></i>
</div>
<h2 class="text-2xl md:text-3xl font-bold text-gray-800">C语言表达式全解析</h2>
</div>
<p class="text-gray-600 text-lg mb-6">从基础语法到复杂工程场景的全面指南,帮助开发者掌握C语言表达式的核心概念和实际应用。</p>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
<div class="bg-secondary rounded-lg p-4 hover:shadow-hover transition-all-300">
<div class="flex items-center mb-2">
<i class="fa fa-book text-primary mr-2"></i>
<h3 class="font-semibold">基础语法</h3>
</div>
<p class="text-sm text-gray-600">运算符优先级、求值顺序、类型转换等核心概念</p>
</div>
<div class="bg-secondary rounded-lg p-4 hover:shadow-hover transition-all-300">
<div class="flex items-center mb-2">
<i class="fa fa-microchip text-primary mr-2"></i>
<h3 class="font-semibold">硬件交互</h3>
</div>
<p class="text-sm text-gray-600">寄存器操作、位带操作、DMA配置、中断管理</p>
</div>
<div class="bg-secondary rounded-lg p-4 hover:shadow-hover transition-all-300">
<div class="flex items-center mb-2">
<i class="fa fa-exchange text-primary mr-2"></i>
<h3 class="font-semibold">通信协议</h3>
</div>
<p class="text-sm text-gray-600">UART、I2C、SPI、CAN总线等协议的C语言实现</p>
</div>
<div class="bg-secondary rounded-lg p-4 hover:shadow-hover transition-all-300">
<div class="flex items-center mb-2">
<i class="fa fa-rocket text-primary mr-2"></i>
<h3 class="font-semibold">高级应用</h3>
</div>
<p class="text-sm text-gray-600">性能优化、安全关键系统、嵌入式特定技巧</p>
</div>
</div>
<div class="bg-gray-100 rounded-lg p-4 border-l-4 border-accent">
<div class="flex items-start">
<i class="fa fa-lightbulb-o text-accent mt-1 mr-3"></i>
<p class="text-gray-700">C语言表达式是嵌入式开发的基础,掌握其特性对于编写高效、可靠的硬件交互代码至关重要。本文档涵盖从基础语法到高级硬件操作的全场景应用。</p>
</div>
</div>
</div>
</section>
<!-- 基础语法部分 -->
<section id="basic" class="mb-12">
<div class="bg-white rounded-xl shadow-card p-6 md:p-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-cogs text-primary"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">一、基础语法与表达式基础</h2>
</div>
<!-- 1.1 运算符优先级与结合性 -->
<div id="priority" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">1.1 运算符优先级与结合性</h3>
<p class="text-gray-600 mb-4">运算符优先级决定了表达式中操作的执行顺序,而结合性则规定了相同优先级运算符的求值方向。</p>
<div class="mb-6 h-64">
<canvas id="priorityChart"></canvas>
</div>
<div class="table-responsive mb-6">
<table class="min-w-full bg-white border border-gray-200 rounded-lg">
<thead>
<tr class="bg-gray-50">
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">优先级</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">运算符类型</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">运算符</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">结合性</th>
</tr>
</thead>
<tbody>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">1</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">括号与成员访问</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`()`、`[]`、`.`、`->`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">2</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">单目运算符</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`++`、`--`、`!`、`~`、`*`、`&`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">右结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">3</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">算术运算符(乘除模)</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`*`、`/`、`%`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">4</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">算术运算符(加减)</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`+`、`-`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">5</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">移位运算符</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`<<`、`>>`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">6</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">关系运算符</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`<`、`<=`、`>`、`>=`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">7</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">相等性判断</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`==`、`!=`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">8</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">按位与</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`&`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">9</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">按位异或</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`^`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">10</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">按位或</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`|`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">11</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">逻辑与</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`&&`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">12</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">逻辑或</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`||`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">左结合</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">13</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">条件运算符</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`?:`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">右结合</td>
</tr>
</tbody>
</table>
</div>
<div class="space-y-4">
<div class="bg-gray-50 p-4 rounded-lg border-l-4 border-primary">
<h5 class="font-medium text-gray-800 mb-2">1. 算术 > 关系 > 逻辑</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>if (a + b > c && d == e) {
// 等价于 ((a + b) > c) && (d == e)
}</code></pre>
</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg border-l-4 border-primary">
<h5 class="font-medium text-gray-800 mb-2">2. 单目右结合</h5>
<p class="text-gray-600 text-sm mb-2">前置自增、取地址等从右向左计算。</p>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>*ptr++; // 等价于 *(ptr++),而非 (*ptr)++</code></pre>
</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg border-l-4 border-primary">
<h5 class="font-medium text-gray-800 mb-2">3. 算术 > 移位 > 关系 > 位运算 > 逻辑</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>result = a + b << 2 & c | d;
// 等价于 ((a + b) << 2) & c) | d</code></pre>
</div>
</div>
</div>
</div>
<!-- 1.2 表达式求值顺序与副作用 -->
<div id="evaluation" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">1.2 表达式求值顺序与副作用</h3>
<p class="text-gray-600 mb-4">C语言只规定了运算符的优先级和结合性,并未明确定义操作数的求值顺序,这可能导致未定义行为(UB)。</p>
<div class="bg-white border border-gray-200 rounded-lg p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2 flex items-center">
<i class="fa fa-exclamation-triangle text-accent mr-2"></i>
未定义行为示例
</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>int i = 5;
int j = i++ + ++i; // 未定义行为!</code></pre>
</div>
<p class="text-gray-600 text-sm mt-2">编译器可能先计算左侧 <code class="bg-gray-100 px-1 py-0.5 rounded text-xs">i</code> 再计算 <code class="bg-gray-100 px-1 py-0.5 rounded text-xs">i++</code>,也可能相反。</p>
</div>
<div class="bg-white border border-gray-200 rounded-lg p-4">
<h5 class="font-medium text-gray-800 mb-2 flex items-center">
<i class="fa fa-exclamation-triangle text-accent mr-2"></i>
副作用(Side Effects)
</h5>
<p class="text-gray-600 text-sm mb-2">副作用指表达式求值过程中对变量或内存状态的修改。常见于:</p>
<ul class="list-disc list-inside text-gray-600 text-sm space-y-1 pl-2 mb-3">
<li>赋值操作:<code class="bg-gray-100 px-1 py-0.5 rounded text-xs">a = 5</code></li>
<li>自增/自减:<code class="bg-gray-100 px-1 py-0.5 rounded text-xs">i++</code>、<code class="bg-gray-100 px-1 py-0.5 rounded text-xs">--j</code></li>
<li>函数调用:<code class="bg-gray-100 px-1 py-0.5 rounded text-xs">printf()</code>(修改I/O缓冲区)</li>
</ul>
<p class="text-gray-600 text-sm font-medium">关键点:副作用的发生时机受求值顺序影响,可能导致意外结果。</p>
</div>
<div class="mt-6">
<h4 class="font-semibold text-gray-800 mb-3">提升表达式可读性的技巧</h4>
<div class="space-y-4 mb-6">
<div>
<h5 class="font-medium text-gray-800 mb-2">分步简化表达式</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 复杂表达式:
result = (a << 2) + (b & 0xFF) || (c > 10);
// 拆解为:
int shift_a = a << 2;
int mask_b = b & 0xFF;
int compare_c = c > 10;
result = (shift_a + mask_b) || compare_c;</code></pre>
</div>
</div>
<div>
<h5 class="font-medium text-gray-800 mb-2">优先使用括号</h5>
<p class="text-gray-600 text-sm">即使熟悉优先级,显式括号可提升代码可读性。</p>
</div>
<div>
<h5 class="font-medium text-gray-800 mb-2">区分 <code class="bg-gray-100 px-1 py-0.5 rounded text-xs">&</code> 和 <code class="bg-gray-100 px-1 py-0.5 rounded text-xs">&&</code></h5>
<p class="text-gray-600 text-sm">按位与和逻辑与的优先级不同,误用可能导致逻辑错误。</p>
</div>
</div>
</div>
</div>
<!-- 1.3 类型转换与隐式转换规则 -->
<div id="conversion" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">1.3 类型转换与隐式转换规则</h3>
<p class="text-gray-600 mb-4">C语言会在特定情况下自动进行类型转换,了解这些规则对于避免数据丢失和逻辑错误至关重要。</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div>
<h5 class="font-medium text-gray-800 mb-1">1. 整数提升</h5>
<p class="text-gray-600 text-sm mb-2">小于int的整数类型会被提升为int或unsigned int。</p>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>char a = 10;
short b = 20;
int c = a + b; // a和b被提升为int类型</code></pre>
</div>
</div>
<div>
<h5 class="font-medium text-gray-800 text-sm mb-1">2. 浮点提升</h5>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>int a = 5;
double b = 2.5;
double result = a + b; // 隐式转换a为double</code></pre>
</div>
</div>
</div>
<h4 class="font-semibold text-gray-800 mb-3">显式类型转换(强制转换)</h4>
<p class="text-gray-600 mb-4">使用强制转换运算符可以显式改变表达式的类型,但需谨慎使用以避免意外结果。</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div>
<h5 class="font-medium text-gray-800 text-sm mb-1">1. 基本类型转换</h5>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>float f = 3.14f;
int i = (int)f; // 显式转换为int,结果为3</code></pre>
</div>
</div>
<div>
<h5 class="font-medium text-gray-800 text-sm mb-1">2. 无符号溢出</h5>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>unsigned short us = 65535; // 无符号短整型最大值
us = us + 1; // 溢出,us变为0</code></pre>
</div>
</div>
<div>
<h5 class="font-medium text-gray-800 text-sm mb-1">3. 指针类型转换(不推荐)</h5>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>int x = 10;
void *vp = &x;
int *ip = (int*)vp; // 显式转换void*到int*</code></pre>
</div>
</div>
</div>
<h4 class="font-semibold text-gray-800 mb-3">常见误区与解决方法</h4>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div class="bg-gray-50 p-3 rounded-lg border border-gray-200">
<h5 class="font-medium text-gray-800 text-sm mb-2">指针转换风险</h5>
<p class="text-gray-600 text-xs mb-2">不当转换可能导致对齐问题或未定义行为。</p>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>int* p = (int*)&c; // 可能引发内存对齐问题</code></pre>
</div>
</div>
<div class="bg-gray-50 p-3 rounded-lg border border-gray-200">
<h5 class="font-medium text-gray-800 text-sm mb-2">精度丢失</h5>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>int i = 3.99; // 隐式转换为3,丢失精度</code></pre>
</div>
<p class="text-gray-600 text-xs">解决方法:使用round()函数或显式处理小数部分。</p>
</div>
<div class="bg-gray-50 p-3 rounded-lg border border-gray-200">
<h5 class="font-medium text-gray-800 text-sm mb-2">符号丢失</h5>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>char c = -1;
unsigned int ui = c; // 符号扩展问题</code></pre>
</div>
<p class="text-gray-600 text-xs">结果:ui变为0xFFFFFFFF而非-1。</p>
</div>
</div>
<h4 class="font-semibold text-gray-800 mb-3">最佳实践</h4>
<ul class="space-y-2 mb-4">
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span class="text-gray-600">检查范围:在进行强制转换前,确保目标类型能容纳源值。</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span class="text-gray-600">避免不必要的转换:设计时选择合适的数据类型,减少类型转换需求。</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span class="text-gray-600">使用类型安全的函数:如 <code class="bg-gray-100 px-1 py-0.5 rounded text-xs">snprintf</code> 替代 <code class="bg-gray-100 px-1 py-0.5 rounded text-xs">sprintf</code>,减少转换错误。</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span class="text-gray-600">明确注释转换意图:</span>
<div class="code-block bg-dark text-white p-2 rounded-md font-mono text-xs ml-2 mt-1">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-0.5 rounded text-[10px]">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>int x = (int)y; // 明确注释转换目的</code></pre>
</div>
</li>
</ul>
</div>
</div>
</section>
<!-- 硬件交互部分 -->
<section id="hardware" class="mb-12">
<div class="bg-white rounded-xl shadow-card p-6 md:p-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-microchip text-primary"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">二、硬件交互与嵌入式系统</h2>
</div>
<!-- 2.1 寄存器位操作表达式 -->
<div id="bit-operation" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">2.1 寄存器位操作表达式</h3>
<p class="text-gray-600 mb-4">嵌入式开发中,寄存器位操作是基础技能,通过位运算可以精确控制硬件外设。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-hover transition-all-300 mb-6">
<h5 class="font-medium text-gray-800 mb-2">GPIO配置示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 假设 GPIOA_MODER 是 GPIOA 的模式寄存器
// 配置 PA5 为输出模式(bit10 和 bit11 设为 01)
CLEAR_BITS(GPIOA_MODER, 0x03 << (5 * 2)); // 清除原有配置
SET_BITS(GPIOA_MODER, 0x01 << (5 * 2)); // 设置为输出模式
// 控制 PA5 输出高低电平
#define LED_PIN 5
#define LED_ON SET_BIT(GPIOA_ODR, LED_PIN)
#define LED_OFF CLEAR_BIT(GPIOA_ODR, LED_PIN)
#define LED_TOGGLE TOGGLE_BIT(GPIOA_ODR, LED_PIN)</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-hover transition-all-300 mb-6">
<h5 class="font-medium text-gray-800 mb-2">UART 配置示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 配置UART波特率、数据位等参数
void UART_Config(void) {
// 使能UART和GPIO时钟
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;
// 配置TX引脚为复用推挽输出
GPIOA->CRH &= ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9);
GPIOA->CRH |= GPIO_CRH_MODE9_1 | GPIO_CRH_CNF9_1;
// 配置RX引脚为浮空输入
GPIOA->CRH &= ~(GPIO_CRH_MODE10 | GPIO_CRH_CNF10);
GPIOA->CRH |= GPIO_CRH_CNF10_0;
// 设置波特率 (假设PCLK2为72MHz)
USART1->BRR = 0x271; // 9600波特率 @ 72MHz
// 使能接收和发送
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
// 使能UART
USART1->CR1 |= USART_CR1_UE;
}
// 使能UART接收中断
USART1->CR1 |= USART_CR1_RXNEIE; // 使能接收缓冲区非空中断
NVIC_EnableIRQ(USART1_IRQn); // 使能NVIC中的UART中断通道</code></pre>
</div>
</div>
<div class="mb-6">
<h4 class="font-semibold text-gray-800 mb-3">常用位操作宏定义</h4>
<div class="table-responsive">
<table class="min-w-full bg-white border border-gray-200 rounded-lg">
<thead>
<tr class="bg-gray-50">
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">操作</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">语法</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">说明</th>
</tr>
</thead>
<tbody>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">置位(Set Bit)</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`REG |= (1 << bit_pos);`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">将特定位设置为1</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">清位(Clear Bit)</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`REG &= ~(1 << bit_pos);`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">将特定位设置为0</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">切换位(Toggle)</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`REG ^= (1 << bit_pos);`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">反转特定位的值</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">检查位(Check)</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">`(REG & (1 << bit_pos)) != 0`</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">判断特定位是否为1</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="bg-secondary p-4 rounded-lg">
<h5 class="font-medium text-gray-800 mb-2">位操作宏定义的通用实现</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>/* 位操作宏定义 */
#define SET_BIT(REG, BIT) ((REG) |= (1U << (BIT)))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(1U << (BIT)))
#define TOGGLE_BIT(REG, BIT) ((REG) ^= (1U << (BIT)))
#define READ_BIT(REG, BIT) (((REG) & (1U << (BIT))) != 0U)
/* 多位操作宏定义 */
#define SET_BITS(REG, MASK) ((REG) |= (MASK))
#define CLEAR_BITS(REG, MASK) ((REG) &= ~(MASK))
#define READ_BITS(REG, MASK) ((REG) & (MASK))
#define WRITE_BITS(REG, MASK, VAL) ((REG) = ((REG) & ~(MASK)) | ((VAL) & (MASK)))
/* 位域操作宏定义 */
#define SET_FIELD(REG, FIELD, VALUE) \
((REG) = ((REG) & ~(FIELD##_MASK)) | ((VALUE) << FIELD##_SHIFT))
#define GET_FIELD(REG, FIELD) \
(((REG) & FIELD##_MASK) >> FIELD##_SHIFT)</code></pre>
</div>
</div>
</div>
<!-- 2.2 位带操作表达式 -->
<div id="bit-banding" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">2.2 位带操作表达式</h3>
<p class="text-gray-600 mb-4">位带操作允许通过普通的加载/存储指令来访问某个比特位,简化了位操作代码,特别适用于Cortex-M系列MCU。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">位带操作原理</h5>
<p class="text-gray-600 text-sm mb-3">位带操作将每个比特位映射到一个32位的字地址,写入这个地址就相当于操作对应的比特位。对于SRAM和外设寄存器分别有不同的位带区域。</p>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 位带操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x02000000 + \
((addr & 0x00FFFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
// 外设位带操作宏定义
#define GPIOA_ODR_Addr (GPIOA_BASE + 0x0C)
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr, n)
// 使用示例
PAout(5) = 1; // 直接设置PA5为高电平,等价于GPIOA->ODR |= (1 << 5)
PAout(5) = 0; // 直接设置PA5为低电平,等价于GPIOA->ODR &= ~(1 << 5)</code></pre>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
<h5 class="font-medium text-gray-800 mb-2">位带操作的优势</h5>
<ul class="space-y-1 text-gray-600 text-sm">
<li class="flex items-start">
<i class="fa fa-check text-green-500 mt-1 mr-2"></i>
<span>代码更简洁,可读性更高</span>
</li>
<li class="flex items-start">
<i class="fa fa-check text-green-500 mt-1 mr-2"></i>
<span>单条指令完成位操作,原子性更好</span>
</li>
<li class="flex items-start">
<i class="fa fa-check text-green-500 mt-1 mr-2"></i>
<span>在RTOS环境下减少临界区需求</span>
</li>
</ul>
</div>
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
<h5 class="font-medium text-gray-800 mb-2">位带操作的局限性</h5>
<ul class="space-y-1 text-gray-600 text-sm">
<li class="flex items-start">
<i class="fa fa-times text-red-500 mt-1 mr-2"></i>
<span>仅限Cortex-M3/M4/M7等支持位带的架构</span>
</li>
<li class="flex items-start">
<i class="fa fa-times text-red-500 mt-1 mr-2"></i>
<span>增加了地址转换的计算量</span>
</li>
<li class="flex items-start">
<i class="fa fa-times text-red-500 mt-1 mr-2"></i>
<span>调试时查看位状态不如直接操作寄存器直观</span>
</li>
</ul>
</div>
</div>
<div class="bg-secondary p-4 rounded-lg">
<h5 class="font-medium text-gray-800 mb-2">位带操作在STM32中的应用</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// STM32位带操作完整宏定义
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
// GPIOA输出位带定义
#define GPIOA_ODR_Addr (GPIOA_BASE + 0x0C)
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n)
// GPIOA输入位带定义
#define GPIOA_IDR_Addr (GPIOA_BASE + 0x08)
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n)
// 使用示例
void LED_Init(void) {
// 初始化GPIOA时钟等配置...
// 使用位带操作控制LED
PAout(5) = 0; // 关闭LED
}
void KEY_Scan(void) {
// 使用位带操作读取按键状态
if(PAin(0) == 0) { // 检测PA0是否按下
delay_ms(20); // 消抖
if(PAin(0) == 0) {
PAout(5) = !PAout(5); // 翻转LED状态
}
}
}</code></pre>
</div>
</div>
</div>
<!-- 2.3 DMA配置与数据传输表达式 -->
<div id="dma" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">2.3 DMA配置与数据传输表达式</h3>
<p class="text-gray-600 mb-4">DMA(直接内存访问)允许外设直接与内存进行数据传输,无需CPU干预,提高系统效率。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">UART DMA发送配置示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>void DMA_Config(void) {
// 使能DMA时钟
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// 复位DMA通道
DMA1_Channel4->CCR = 0;
// 配置DMA通道
DMA1_Channel4->CCR |= DMA_CCR_DIR; // 存储器到外设
DMA1_Channel4->CCR |= DMA_CCR_MINC; // 存储器地址增量
DMA1_Channel4->CCR &= ~DMA_CCR_PINC; // 外设地址不增量
DMA1_Channel4->CCR |= DMA_CCR_MSIZE_0; // 存储器数据宽度16位
DMA1_Channel4->CCR |= DMA_CCR_PSIZE_0; // 外设数据宽度16位
DMA1_Channel4->CCR |= DMA_CCR_PL_1; // 高优先级
// 配置外设地址 (UART1数据寄存器)
DMA1_Channel4->CPAR = (uint32_t)&USART1->DR;
}
// DMA发送函数
void UART_DMA_Send(uint8_t *data, uint16_t len) {
// 关闭DMA通道
DMA1_Channel4->CCR &= ~DMA_CCR_EN;
// 设置传输数据长度
DMA1_Channel4->CNDTR = len;
// 设置存储器地址
DMA1_Channel4->CMAR = (uint32_t)data;
// 使能DMA通道
DMA1_Channel4->CCR |= DMA_CCR_EN;
// 使能UART DMA发送
USART1->CR3 |= USART_CR3_DMAT;
}
// 检查DMA传输是否完成
uint8_t DMA_TransferComplete(void) {
return (DMA1->ISR & DMA_ISR_TCIF4) ? 1 : 0;
}
// 清除DMA传输完成标志
void DMA_ClearTransferCompleteFlag(void) {
DMA1->IFCR |= DMA_IFCR_CTCIF4;
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">ADC DMA采集配置示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>uint16_t adc_value[3]; // 存储3个ADC通道的转换结果
void ADC_DMA_Config(void) {
// 使能DMA1时钟
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// 配置DMA通道1 (ADC1)
DMA1_Channel1->CCR = 0;
DMA1_Channel1->CCR &= ~DMA_CCR_DIR; // 外设到存储器
DMA1_Channel1->CCR |= DMA_CCR_MINC; // 存储器地址增量
DMA1_Channel1->CCR &= ~DMA_CCR_PINC; // 外设地址不增量
DMA1_Channel1->CCR |= DMA_CCR_MSIZE_0; // 存储器数据宽度16位
DMA1_Channel1->CCR &= ~DMA_CCR_PSIZE_0; // 外设数据宽度16位
DMA1_Channel1->CCR |= DMA_CCR_CIRC; // 循环模式
DMA1_Channel1->CCR |= DMA_CCR_PL_0; // 中优先级
// 配置外设地址 (ADC1数据寄存器)
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
// 配置存储器地址和传输长度
DMA1_Channel1->CMAR = (uint32_t)adc_value;
DMA1_Channel1->CNDTR = 3; // 3个通道
// 使能DMA通道
DMA1_Channel1->CCR |= DMA_CCR_EN;
}
void ADC_Config(void) {
// 使能ADC1时钟
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
// ADC配置
ADC1->CR1 = 0;
ADC1->CR1 |= ADC_CR1_SCAN; // 扫描模式
ADC1->CR2 = 0;
ADC1->CR2 |= ADC_CR2_CONT; // 连续转换模式
ADC1->CR2 |= ADC_CR2_DMA; // DMA模式使能
ADC1->CR2 |= ADC_CR2_ADON; // 使能ADC
// 配置采样时间
ADC1->SMPR2 = 0;
ADC1->SMPR2 |= ADC_SMPR2_SMP0_2 | ADC_SMPR2_SMP0_1 | ADC_SMPR2_SMP0_0; // 通道0采样时间
ADC1->SMPR2 |= ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0; // 通道1采样时间
ADC1->SMPR2 |= ADC_SMPR2_SMP2_2 | ADC_SMPR2_SMP2_1 | ADC_SMPR2_SMP2_0; // 通道2采样时间
// 配置转换序列
ADC1->SQR3 = 0;
ADC1->SQR3 |= 0 << 0; // 第1个转换:通道0
ADC1->SQR3 |= 1 << 5; // 第2个转换:通道1
ADC1->SQR3 |= 2 << 10; // 第3个转换:通道2
ADC1->SQR1 &= ~ADC_SQR1_L; // 3个转换
// 开始转换
ADC1->CR2 |= ADC_CR2_SWSTART;
}</code></pre>
</div>
</div>
<div class="bg-secondary p-4 rounded-lg mb-6">
<h4 class="font-semibold text-gray-800 mb-2">DMA使用注意事项</h4>
<ul class="space-y-2 text-gray-700">
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-primary mt-1 mr-2"></i>
<span>确保DMA传输的内存地址正确对齐,特别是对于大于8位的数据宽度。</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-primary mt-1 mr-2"></i>
<span>在重新配置DMA前,先关闭DMA通道,避免错误传输。</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-primary mt-1 mr-2"></i>
<span>对于循环模式,确保缓冲区足够大,避免数据覆盖。</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-primary mt-1 mr-2"></i>
<span>使用DMA中断时,及时清除中断标志位。</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-primary mt-1 mr-2"></i>
<span>在高速传输时,注意选择合适的DMA优先级,避免通道间的饥饿现象。</span>
</li>
</ul>
</div>
</div>
<!-- 2.4 中断优先级管理表达式 -->
<div id="interrupt" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">2.4 中断优先级管理表达式</h3>
<p class="text-gray-600 mb-4">中断优先级决定了多个中断同时发生时的响应顺序,合理设置优先级对系统稳定性至关重要。</p>
<div class="table-responsive mb-6">
<table class="min-w-full bg-white border border-gray-200 rounded-lg">
<thead>
<tr class="bg-gray-50">
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">中断分组</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">抢占优先级位数</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">子优先级位数</th>
<th class="py-3 px-4 border-b text-left text-sm font-semibold text-gray-700">优先级计算公式</th>
</tr>
</thead>
<tbody>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">NVIC_PRIORITYGROUP_0</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">0</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">4</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">priority = SubPriority & 0x0F</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">NVIC_PRIORITYGROUP_1</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">1</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">3</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">priority = (Preempt & 0x01) << 3 | (Sub & 0x07)</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">NVIC_PRIORITYGROUP_2</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">2</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">2</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">priority = (Preempt & 0x03) << 2 | (Sub & 0x03)</td>
</tr>
<tr class="hover:bg-gray-50">
<td class="py-2 px-4 border-b text-sm text-gray-700">NVIC_PRIORITYGROUP_3</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">3</td>
<td class="py-2 px-4 border-b text-sm text-gray-700">1</td>
<td class="py-2 px-4 border-b text-sm text-gray-700 font-mono">priority = (Preempt & 0x07) << 1 | (Sub & 0x01)</td>
</tr>
</tbody>
</table>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">中断优先级配置示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>void NVIC_Configuration(void) {
NVIC_InitTypeDef NVIC_InitStructure;
// 设置中断分组为2:2位抢占优先级,2位响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置USART1中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 配置TIM2中断(更高优先级)
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级0(更高)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 配置EXTI0中断(更低优先级)
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级2(更低)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">中断服务程序示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// UART1中断服务程序
void USART1_IRQHandler(void) {
uint8_t data;
// 接收中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
// 读取接收数据
data = USART_ReceiveData(USART1);
// 将数据存入缓冲区
uart_rx_buffer[uart_rx_index++] = data;
// 检查缓冲区是否已满
if(uart_rx_index >= UART_BUFFER_SIZE) {
uart_rx_index = 0; // 循环缓冲区
}
// 清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
// 发送完成中断
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {
if(uart_tx_index < uart_tx_length) {
// 发送下一个字节
USART_SendData(USART1, uart_tx_buffer[uart_tx_index++]);
} else {
// 发送完成,关闭发送中断
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
uart_tx_busy = 0; // 标记发送完成
}
// 清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_TXE);
}
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 hover:shadow-hover transition-all-300">
<h5 class="font-medium text-gray-800 mb-2">中断服务程序注意事项</h5>
<ul class="space-y-2 text-gray-600 text-sm">
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-accent mt-1 mr-2"></i>
<span>保持ISR简短,避免在中断中执行耗时操作</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-accent mt-1 mr-2"></i>
<span>及时清除中断标志,避免无限进入中断</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-accent mt-1 mr-2"></i>
<span>访问共享资源时使用临界区保护</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-accent mt-1 mr-2"></i>
<span>避免在ISR中使用浮点数运算(可能需要额外配置)</span>
</li>
<li class="flex items-start">
<i class="fa fa-exclamation-circle text-accent mt-1 mr-2"></i>
<span>中断嵌套需要正确配置抢占优先级</span>
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- 通信协议部分 -->
<section id="communication" class="mb-12">
<div class="bg-white rounded-xl shadow-card p-6 md:p-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-exchange text-primary"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">三、通信协议与数据处理</h2>
</div>
<!-- 3.1 UART通信协议 -->
<div id="uart" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">3.1 UART通信协议</h3>
<p class="text-gray-600 mb-4">UART(通用异步收发传输器)是一种异步串行通信协议,广泛用于短距离设备间通信。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">UART数据帧结构</h5>
<div class="flex flex-col items-center mb-4">
<div class="w-full max-w-md bg-gray-100 p-4 rounded-lg">
<div class="flex text-center text-xs">
<div class="flex-1 border border-gray-300 p-1 bg-gray-200">起始位 (0)</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位0</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位1</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位2</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位3</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位4</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位5</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位6</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">数据位7</div>
<div class="flex-1 border-t border-b border-gray-300 p-1">校验位</div>
<div class="flex-1 border border-gray-300 p-1 bg-gray-200">停止位 (1)</div>
</div>
</div>
</div>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// UART帧接收与解析
typedef struct {
uint8_t start_byte; // 帧起始符
uint8_t device_addr; // 设备地址
uint8_t cmd; // 命令字
uint8_t data_len; // 数据长度
uint8_t data[64]; // 数据域
uint8_t checksum; // 校验和
uint8_t end_byte; // 帧结束符
} UART_FrameTypeDef;
UART_FrameTypeDef uart_frame;
uint8_t frame_receive_state = 0;
uint8_t data_receive_count = 0;
// 解析UART接收的数据
void UART_FrameParse(uint8_t data) {
switch(frame_receive_state) {
case 0: // 等待起始符
if(data == 0xAA) {
uart_frame.start_byte = data;
frame_receive_state = 1;
}
break;
case 1: // 接收设备地址
uart_frame.device_addr = data;
frame_receive_state = 2;
break;
case 2: // 接收命令字
uart_frame.cmd = data;
frame_receive_state = 3;
break;
case 3: // 接收数据长度
uart_frame.data_len = data;
data_receive_count = 0;
frame_receive_state = (data > 0) ? 4 : 5;
break;
case 4: // 接收数据
uart_frame.data[data_receive_count++] = data;
if(data_receive_count >= uart_frame.data_len) {
frame_receive_state = 5;
}
break;
case 5: // 接收校验和
uart_frame.checksum = data;
frame_receive_state = 6;
break;
case 6: // 接收结束符
if(data == 0x55) {
uart_frame.end_byte = data;
// 校验和验证
uint8_t checksum = uart_frame.start_byte + uart_frame.device_addr +
uart_frame.cmd + uart_frame.data_len;
for(uint8_t i = 0; i < uart_frame.data_len; i++) {
checksum += uart_frame.data[i];
}
if(checksum == uart_frame.checksum) {
// 帧接收正确,处理数据
UART_FrameProcess(&uart_frame);
} else {
// 校验和错误,处理错误
}
}
// 重置状态机
frame_receive_state = 0;
break;
default:
frame_receive_state = 0;
break;
}
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">UART命令处理与响应</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 处理接收到的UART帧
void UART_FrameProcess(UART_FrameTypeDef *frame) {
// 检查设备地址是否匹配(广播地址0xFF除外)
if(frame->device_addr != DEVICE_ADDR && frame->device_addr != 0xFF) {
return; // 地址不匹配,不处理
}
// 根据命令字处理不同命令
switch(frame->cmd) {
case CMD_GET_VERSION:
UART_SendVersion(frame->device_addr);
break;
case CMD_SET_PARAM:
if(frame->data_len == 2) {
UART_SetParameter(frame->data[0], frame->data[1]);
UART_SendAck(frame->device_addr, ACK_SUCCESS);
} else {
UART_SendAck(frame->device_addr, ACK_INVALID_LENGTH);
}
break;
case CMD_GET_DATA:
UART_SendData(frame->device_addr);
break;
case CMD_RESET:
UART_SendAck(frame->device_addr, ACK_SUCCESS);
// 延时确保ACK发送完成
delay_ms(10);
// 软件复位
NVIC_SystemReset();
break;
default:
UART_SendAck(frame->device_addr, ACK_INVALID_CMD);
break;
}
}
// 发送响应帧
void UART_SendFrame(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) {
uint8_t tx_buffer[128];
uint8_t index = 0;
// 填充帧头
tx_buffer[index++] = 0xAA; // 起始符
tx_buffer[index++] = addr; // 目标地址
tx_buffer[index++] = cmd; // 命令字
tx_buffer[index++] = len; // 数据长度
// 填充数据
for(uint8_t i = 0; i < len; i++) {
tx_buffer[index++] = data[i];
}
// 计算校验和
uint8_t checksum = 0;
for(uint8_t i = 0; i < index; i++) {
checksum += tx_buffer[i];
}
tx_buffer[index++] = checksum;
// 填充帧尾
tx_buffer[index++] = 0x55; // 结束符
// 发送帧数据
UART_DMA_Send(tx_buffer, index);
}</code></pre>
</div>
</div>
</div>
<!-- 3.2 I2C通信协议 -->
<div id="i2c" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">3.2 I2C通信协议</h3>
<p class="text-gray-600 mb-4">I2C(Inter-Integrated Circuit)是一种双线串行通信协议,使用SDA(数据线)和SCL(时钟线)进行通信,支持多主多从模式。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">I2C基本操作函数</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// I2C起始信号
void I2C_Start(void) {
SDA_HIGH();
SCL_HIGH();
I2C_Delay();
SDA_LOW(); // 当SCL为高电平时,SDA由高变低为起始信号
I2C_Delay();
SCL_LOW(); // 钳住SCL线,准备发送或接收数据
I2C_Delay();
}
// I2C停止信号
void I2C_Stop(void) {
SDA_LOW();
SCL_HIGH();
I2C_Delay();
SDA_HIGH(); // 当SCL为高电平时,SDA由低变高为停止信号
I2C_Delay();
}
// 发送应答信号
void I2C_Ack(void) {
SDA_LOW(); // 应答信号:0
I2C_Delay();
SCL_HIGH();
I2C_Delay();
SCL_LOW();
I2C_Delay();
SDA_HIGH(); // 释放SDA线
}
// 发送非应答信号
void I2C_NAck(void) {
SDA_HIGH(); // 非应答信号:1
I2C_Delay();
SCL_HIGH();
I2C_Delay();
SCL_LOW();
I2C_Delay();
}
// 等待应答信号
uint8_t I2C_WaitAck(void) {
uint8_t ack_flag = 1;
SDA_HIGH(); // 释放SDA线
I2C_Delay();
SCL_HIGH();
I2C_Delay();
if(SDA_READ()) { // 读取SDA线状态
ack_flag = 0; // 未收到应答
} else {
ack_flag = 1; // 收到应答
}
SCL_LOW();
I2C_Delay();
return ack_flag;
}
// 发送一个字节
void I2C_SendByte(uint8_t data) {
for(uint8_t i = 0; i < 8; i++) {
if(data & 0x80) { // 发送最高位
SDA_HIGH();
} else {
SDA_LOW();
}
I2C_Delay();
SCL_HIGH();
I2C_Delay();
SCL_LOW();
data <<= 1; // 左移一位,准备发送下一位
}
}
// 接收一个字节
uint8_t I2C_ReceiveByte(void) {
uint8_t data = 0;
SDA_HIGH(); // 释放SDA线
for(uint8_t i = 0; i < 8; i++) {
SCL_HIGH();
I2C_Delay();
data <<= 1; // 左移一位
if(SDA_READ()) {
data |= 0x01; // 读取SDA线状态
}
SCL_LOW();
I2C_Delay();
}
return data;
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">I2C设备读写操作</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 向I2C设备指定地址写入一个字节
uint8_t I2C_WriteByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t data) {
I2C_Start();
// 发送设备写地址(7位地址 + 0表示写)
I2C_SendByte((dev_addr << 1) | 0x00);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 发送寄存器地址
I2C_SendByte(reg_addr);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 发送数据
I2C_SendByte(data);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
I2C_Stop();
return 1; // 写入成功
}
// 从I2C设备指定地址读取一个字节
uint8_t I2C_ReadByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data) {
if(data == NULL) return 0;
// 第一步:写入要读取的寄存器地址
I2C_Start();
// 发送设备写地址
I2C_SendByte((dev_addr << 1) | 0x00);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 发送寄存器地址
I2C_SendByte(reg_addr);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 第二步:读取数据
I2C_Start(); // 重新发送起始信号
// 发送设备读地址(7位地址 + 1表示读)
I2C_SendByte((dev_addr << 1) | 0x01);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 读取数据
*data = I2C_ReceiveByte();
I2C_NAck(); // 发送非应答信号,表示读取结束
I2C_Stop();
return 1; // 读取成功
}
// 从I2C设备读取多个字节
uint8_t I2C_ReadBytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len) {
if(data == NULL || len == 0) return 0;
// 第一步:写入要读取的寄存器地址
I2C_Start();
// 发送设备写地址
I2C_SendByte((dev_addr << 1) | 0x00);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 发送寄存器地址
I2C_SendByte(reg_addr);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 第二步:读取数据
I2C_Start(); // 重新发送起始信号
// 发送设备读地址
I2C_SendByte((dev_addr << 1) | 0x01);
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 设备无应答
}
// 读取多个字节
for(uint8_t i = 0; i < len; i++) {
data[i] = I2C_ReceiveByte();
// 最后一个字节发送非应答,其他发送应答
if(i < len - 1) {
I2C_Ack();
} else {
I2C_NAck();
}
}
I2C_Stop();
return len; // 返回读取的字节数
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4">
<h5 class="font-medium text-gray-800 mb-2">I2C设备应用示例(读取温湿度传感器)</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 温湿度传感器操作示例 (如SHT30)
#define SHT30_ADDR 0x44 // SHT30设备地址
// 初始化SHT30传感器
uint8_t SHT30_Init(void) {
// 发送软复位命令
uint8_t reset_cmd[2] = {0x30, 0xA2};
I2C_Start();
I2C_SendByte((SHT30_ADDR << 1) | 0x00); // 写地址
if(!I2C_WaitAck()) {
I2C_Stop();
return 0; // 传感器无应答
}
// 发送复位命令
I2C_SendByte(reset_cmd[0]);
I2C_WaitAck();
I2C_SendByte(reset_cmd[1]);
I2C_WaitAck();
I2C_Stop();
delay_ms(10); // 等待复位完成
return 1; // 初始化成功
}
// 读取温湿度数据
uint8_t SHT30_ReadData(float *temp, float *humidity) {
if(temp == NULL || humidity == NULL) return 0;
// 发送测量命令(单次测量,高精度)
uint8_t cmd[2] = {0x2C, 0x06};
uint8_t data[6];
// 发送测量命令
I2C_Start();
I2C_SendByte((SHT30_ADDR << 1) | 0x00); // 写地址
if(!I2C_WaitAck()) {
I2C_Stop();
return 0;
}
I2C_SendByte(cmd[0]);
I2C_WaitAck();
I2C_SendByte(cmd[1]);
I2C_WaitAck();
I2C_Stop();
// 等待测量完成
delay_ms(50);
// 读取测量结果
I2C_Start();
I2C_SendByte((SHT30_ADDR << 1) | 0x01); // 读地址
if(!I2C_WaitAck()) {
I2C_Stop();
return 0;
}
// 读取6个字节数据
for(uint8_t i = 0; i < 6; i++) {
data[i] = I2C_ReceiveByte();
if(i < 5) {
I2C_Ack();
} else {
I2C_NAck();
}
}
I2C_Stop();
// 校验数据(简单校验,实际应使用CRC)
if((data[1] & 0x0F) != 0) {
return 0; // 数据错误
}
// 计算温度和湿度
uint16_t temp_raw = (data[0] << 8) | data[1];
uint16_t humi_raw = (data[3] << 8) | data[4];
*temp = (temp_raw / 65535.0f) * 175.0f - 45.0f; // 温度转换公式
*humidity = (humi_raw / 65535.0f) * 100.0f; // 湿度转换公式
return 1; // 读取成功
}</code></pre>
</div>
</div>
</div>
<!-- 3.3 SPI通信协议 -->
<div id="spi" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">3.3 SPI通信协议</h3>
<p class="text-gray-600 mb-4">SPI(Serial Peripheral Interface)是一种高速全双工同步通信总线,通常使用4根线:SCLK(时钟)、MOSI(主机输出从机输入)、MISO(主机输入从机输出)和SS(从机选择)。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">SPI初始化与基本操作</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// SPI初始化
void SPI_Init(void) {
// 使能SPI和GPIO时钟
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_IOPAEN;
// 配置SPI引脚
// SCK - PA5, MOSI - PA7, MISO - PA6, NSS - PA4
GPIOA->CRL &= ~(GPIO_CRL_MODE5 | GPIO_CRL_CNF5);
GPIOA->CRL |= GPIO_CRL_MODE5_1 | GPIO_CRL_MODE5_0; // 推挽输出50MHz
GPIOA->CRL |= GPIO_CRL_CNF5_1; // 复用推挽输出
GPIOA->CRL &= ~(GPIO_CRL_MODE7 | GPIO_CRL_CNF7);
GPIOA->CRL |= GPIO_CRL_MODE7_1 | GPIO_CRL_MODE7_0; // 推挽输出50MHz
GPIOA->CRL |= GPIO_CRL_CNF7_1; // 复用推挽输出
GPIOA->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6);
GPIOA->CRL |= GPIO_CRL_CNF6_0; // 浮空输入
GPIOA->CRL &= ~(GPIO_CRL_MODE4 | GPIO_CRL_CNF4);
GPIOA->CRL |= GPIO_CRL_MODE4_1 | GPIO_CRL_MODE4_0; // 推挽输出50MHz
GPIOA->CRL |= GPIO_CRL_CNF4_0; // 通用推挽输出
// 拉高NSS
GPIOA->BSRR = GPIO_BSRR_BS4;
// 配置SPI
SPI1->CR1 = 0;
SPI1->CR1 |= SPI_CR1_MSTR; // 主机模式
SPI1->CR1 |= SPI_CR1_BR_1; // 分频8,APB2=72MHz,SPI时钟=9MHz
SPI1->CR1 &= ~SPI_CR1_CPOL; // 时钟极性,空闲时为低
SPI1->CR1 &= ~SPI_CR1_CPHA; // 时钟相位,第一个时钟沿采样
SPI1->CR1 &= ~SPI_CR1_DFF; // 8位数据格式
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; // 高位在前
SPI1->CR1 |= SPI_CR1_SSM; // 软件管理NSS
SPI1->CR1 |= SPI_CR1_SSI; // 内部NSS置高
// 使能SPI
SPI1->CR1 |= SPI_CR1_SPE;
}
// SPI发送一个字节
uint8_t SPI_SendByte(uint8_t data) {
// 等待发送缓冲区为空
while((SPI1->SR & SPI_SR_TXE) == 0);
// 发送数据
SPI1->DR = data;
// 等待发送完成
while((SPI1->SR & SPI_SR_BSY) != 0);
// 返回接收缓冲区数据(全双工)
return SPI1->DR;
}
// SPI接收一个字节
uint8_t SPI_ReceiveByte(void) {
// 发送 dummy 数据以产生时钟
return SPI_SendByte(0xFF);
}
// SPI发送多个字节
void SPI_SendBytes(uint8_t *data, uint16_t len) {
if(data == NULL || len == 0) return;
for(uint16_t i = 0; i < len; i++) {
SPI_SendByte(data[i]);
}
}
// SPI接收多个字节
void SPI_ReceiveBytes(uint8_t *data, uint16_t len) {
if(data == NULL || len == 0) return;
for(uint16_t i = 0; i < len; i++) {
data[i] = SPI_ReceiveByte();
}
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">SPI设备操作示例(读写Flash存储器)</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// SPI Flash操作示例 (如W25Q系列)
#define FLASH_CS_LOW() GPIOA->BSRR = GPIO_BSRR_BR4 // 拉低片选
#define FLASH_CS_HIGH() GPIOA->BSRR = GPIO_BSRR_BS4 // 拉高片选
// 读取Flash ID
uint32_t Flash_ReadID(void) {
uint32_t id = 0;
FLASH_CS_LOW();
SPI_SendByte(0x9F); // 读取ID命令
// 读取3字节ID
id |= (uint32_t)SPI_ReceiveByte() << 16;
id |= (uint32_t)SPI_ReceiveByte() << 8;
id |= SPI_ReceiveByte();
FLASH_CS_HIGH();
return id;
}
// 擦除Flash扇区
void Flash_EraseSector(uint32_t addr) {
// 发送写使能命令
FLASH_CS_LOW();
SPI_SendByte(0x06); // 写使能
FLASH_CS_HIGH();
// 发送扇区擦除命令
FLASH_CS_LOW();
SPI_SendByte(0x20); // 扇区擦除命令
// 发送地址
SPI_SendByte((addr >> 16) & 0xFF);
SPI_SendByte((addr >> 8) & 0xFF);
SPI_SendByte(addr & 0xFF);
FLASH_CS_HIGH();
// 等待擦除完成
while(Flash_ReadStatus() & 0x01);
}
// 读取Flash状态寄存器
uint8_t Flash_ReadStatus(void) {
uint8_t status;
FLASH_CS_LOW();
SPI_SendByte(0x05); // 读状态寄存器命令
status = SPI_ReceiveByte();
FLASH_CS_HIGH();
return status;
}
// 向Flash写入数据
void Flash_WritePage(uint32_t addr, uint8_t *data, uint16_t len) {
if(data == NULL || len == 0) return;
// 发送写使能命令
FLASH_CS_LOW();
SPI_SendByte(0x06); // 写使能
FLASH_CS_HIGH();
// 发送页编程命令
FLASH_CS_LOW();
SPI_SendByte(0x02); // 页编程命令
// 发送地址
SPI_SendByte((addr >> 16) & 0xFF);
SPI_SendByte((addr >> 8) & 0xFF);
SPI_SendByte(addr & 0xFF);
// 发送数据
SPI_SendBytes(data, len);
FLASH_CS_HIGH();
// 等待写入完成
while(Flash_ReadStatus() & 0x01);
}
// 从Flash读取数据
void Flash_ReadData(uint32_t addr, uint8_t *data, uint16_t len) {
if(data == NULL || len == 0) return;
// 发送读数据命令
FLASH_CS_LOW();
SPI_SendByte(0x03); // 读数据命令
// 发送地址
SPI_SendByte((addr >> 16) & 0xFF);
SPI_SendByte((addr >> 8) & 0xFF);
SPI_SendByte(addr & 0xFF);
// 接收数据
SPI_ReceiveBytes(data, len);
FLASH_CS_HIGH();
}</code></pre>
</div>
</div>
</div>
<!-- 3.4 CAN总线协议 -->
<div id="can" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">3.4 CAN总线协议</h3>
<p class="text-gray-600 mb-4">CAN(Controller Area Network)是一种多主方式的串行通信总线,具有较高的抗电磁干扰能力,广泛应用于汽车电子和工业控制领域。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">CAN初始化与基本操作</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// CAN消息结构体
typedef struct {
uint32_t id; // 消息ID
uint8_t data[8]; // 数据
uint8_t len; // 数据长度
uint8_t extended; // 是否为扩展帧
} CAN_MessageTypeDef;
// CAN初始化 (500kbps @ 36MHz)
void CAN_Init(void) {
// 使能CAN和GPIO时钟
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 配置CAN引脚
// CAN_RX - PA11, CAN_TX - PA12
GPIOA->CRH &= ~(GPIO_CRH_MODE11 | GPIO_CRH_CNF11);
GPIOA->CRH |= GPIO_CRH_CNF11_1; // 复用功能输入
GPIOA->CRH &= ~(GPIO_CRH_MODE12 | GPIO_CRH_CNF12);
GPIOA->CRH |= GPIO_CRH_MODE12_1; // 输出50MHz
GPIOA->CRH |= GPIO_CRH_CNF12_1; // 复用推挽输出
// 进入初始化模式
CAN1->MCR |= CAN_MCR_INRQ;
while((CAN1->MSR & CAN_MSR_INAK) == 0); // 等待初始化确认
// 配置波特率 (500kbps)
// 36MHz / ( (1+8+3) * 3 ) = 500kbps
CAN1->BTR &= ~(CAN_BTR_BRP | CAN_BTR_TS1 | CAN_BTR_TS2 | CAN_BTR_SJW);
CAN1->BTR |= 2 << 0; // BRP=3 (分频系数3)
CAN1->BTR |= 7 << 16; // TS1=8TQ
CAN1->BTR |= 2 << 20; // TS2=3TQ
CAN1->BTR |= 0 << 24; // SJW=1TQ
// 退出初始化模式
CAN1->MCR &= ~CAN_MCR_INRQ;
while((CAN1->MSR & CAN_MSR_INAK) != 0); // 等待初始化模式退出
// 配置接收过滤器
CAN1->FMR |= CAN_FMR_FINIT; // 过滤器初始化模式
// 过滤器0配置:32位掩码模式,接收所有ID
CAN1->FA1R &= ~CAN_FA1R_FACT0; // 禁用过滤器0
CAN1->FS1R |= CAN_FS1R_FSC0; // 过滤器0为32位宽
CAN1->FM1R &= ~CAN_FM1R_FM0; // 过滤器0为掩码模式
// 过滤器ID寄存器
CAN1->sFilterRegister[0].FR1 = 0x00000000;
CAN1->sFilterRegister[0].FR2 = 0x00000000; // 掩码0,接收所有ID
CAN1->FFA1R &= ~CAN_FFA1R_FFA0; // 过滤器0关联到FIFO0
CAN1->FA1R |= CAN_FA1R_FACT0; // 使能过滤器0
CAN1->FMR &= ~CAN_FMR_FINIT; // 退出过滤器初始化模式
}
// 发送CAN消息
uint8_t CAN_SendMessage(CAN_MessageTypeDef *msg) {
if(msg == NULL || msg->len > 8) return 0;
uint8_t tx_mailbox;
// 查找空的发送邮箱
if((CAN1->TSR & CAN_TSR_TME0) != 0) {
tx_mailbox = 0;
} else if((CAN1->TSR & CAN_TSR_TME1) != 0) {
tx_mailbox = 1;
} else if((CAN1->TSR & CAN_TSR_TME2) != 0) {
tx_mailbox = 2;
} else {
return 0; // 无空邮箱
}
// 配置消息ID
if(msg->extended) {
// 扩展帧 (29位ID)
CAN1->sTxMailBox[tx_mailbox].TIR = (msg->id << 3) | CAN_TIR_IDE | CAN_TIR_TXRQ;
} else {
// 标准帧 (11位ID)
CAN1->sTxMailBox[tx_mailbox].TIR = (msg->id << 21) | CAN_TIR_TXRQ;
}
// 配置数据长度
CAN1->sTxMailBox[tx_mailbox].TDTR &= ~CAN_TDTR_DLC;
CAN1->sTxMailBox[tx_mailbox].TDTR |= msg->len & CAN_TDTR_DLC;
// 填充数据
for(uint8_t i = 0; i < msg->len; i++) {
CAN1->sTxMailBox[tx_mailbox].TDLR = (CAN1->sTxMailBox[tx_mailbox].TDLR & ~(0xFF << (i * 8))) |
(msg->data[i] << (i * 8));
}
// 等待发送完成
while((CAN1->TSR & (CAN_TSR_TXOK0 << tx_mailbox)) == 0) {
// 检查是否发送超时或出错
if((CAN1->TSR & (CAN_TSR_TERR0 << tx_mailbox)) != 0 ||
(CAN1->TSR & (CAN_TSR_ALST0 << tx_mailbox)) != 0) {
// 清除错误标志
CAN1->TSR |= (CAN_TSR_ABRQ0 << tx_mailbox);
return 0; // 发送失败
}
}
return 1; // 发送成功
}
// 接收CAN消息
uint8_t CAN_ReceiveMessage(CAN_MessageTypeDef *msg) {
if(msg == NULL) return 0;
// 检查FIFO0是否有数据
if((CAN1->RF0R & CAN_RF0R_FMP0) == 0) {
return 0; // 无数据
}
// 读取消息ID
if(CAN1->sFIFOMailBox[0].RIR & CAN_RIR_IDE) {
// 扩展帧
msg->extended = 1;
msg->id = (CAN1->sFIFOMailBox[0].RIR >> 3) & 0x1FFFFFFF;
} else {
// 标准帧
msg->extended = 0;
msg->id = (CAN1->sFIFOMailBox[0].RIR >> 21) & 0x7FF;
}
// 读取数据长度
msg->len = CAN1->sFIFOMailBox[0].RDTR & CAN_RDTR_DLC;
// 读取数据
for(uint8_t i = 0; i < msg->len; i++) {
if(i < 4) {
msg->data[i] = (CAN1->sFIFOMailBox[0].RDLR >> (i * 8)) & 0xFF;
} else {
msg->data[i] = (CAN1->sFIFOMailBox[0].RDHR >> ((i - 4) * 8)) & 0xFF;
}
}
// 释放FIFO0
CAN1->RF0R |= CAN_RF0R_RFOM0;
return 1; // 接收成功
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4">
<h5 class="font-medium text-gray-800 mb-2">CAN消息处理与应用示例</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// CAN消息ID定义
#define CAN_ID_SENSOR_DATA 0x123 // 传感器数据
#define CAN_ID_CONTROL_CMD 0x456 // 控制命令
#define CAN_ID_STATUS_INFO 0x789 // 状态信息
#define CAN_ID_ERROR_INFO 0xABC // 错误信息
// 传感器数据结构体
typedef struct {
float temperature; // 温度 (°C)
float humidity; // 湿度 (%)
float pressure; // 压力 (kPa)
uint8_t sensor_id; // 传感器ID
} SensorData;
// 控制命令结构体
typedef struct {
uint8_t device_id; // 设备ID
uint8_t cmd; // 命令
uint16_t param1; // 参数1
uint16_t param2; // 参数2
} ControlCmd;
// 发送传感器数据
void CAN_SendSensorData(SensorData *data) {
if(data == NULL) return;
CAN_MessageTypeDef msg;
msg.id = CAN_ID_SENSOR_DATA;
msg.extended = 0; // 标准帧
msg.len = 8;
// 将浮点数转换为字节(注意字节序)
uint8_t *temp_ptr = (uint8_t*)&data->temperature;
uint8_t *humi_ptr = (uint8_t*)&data->humidity;
uint8_t *pres_ptr = (uint8_t*)&data->pressure;
msg.data[0] = temp_ptr[0];
msg.data[1] = temp_ptr[1];
msg.data[2] = temp_ptr[2];
msg.data[3] = temp_ptr[3];
msg.data[4] = humi_ptr[0];
msg.data[5] = humi_ptr[1];
msg.data[6] = pres_ptr[0];
msg.data[7] = data->sensor_id;
CAN_SendMessage(&msg);
}
// 解析控制命令
uint8_t CAN_ParseControlCmd(CAN_MessageTypeDef *msg, ControlCmd *cmd) {
if(msg == NULL || cmd == NULL || msg->id != CAN_ID_CONTROL_CMD || msg->len != 6) {
return 0; // 不是有效的控制命令
}
cmd->device_id = msg->data[0];
cmd->cmd = msg->data[1];
cmd->param1 = (msg->data[2] << 8) | msg->data[3];
cmd->param2 = (msg->data[4] << 8) | msg->data[5];
return 1; // 解析成功
}
// CAN消息处理任务
void CAN_ProcessTask(void) {
CAN_MessageTypeDef msg;
ControlCmd cmd;
// 检查是否有新消息
if(CAN_ReceiveMessage(&msg)) {
// 根据消息ID处理不同类型的消息
switch(msg.id) {
case CAN_ID_CONTROL_CMD:
// 解析控制命令
if(CAN_ParseControlCmd(&msg, &cmd)) {
// 处理控制命令
ProcessControlCommand(&cmd);
}
break;
case CAN_ID_STATUS_INFO:
// 处理状态信息
ProcessStatusInfo(&msg);
break;
case CAN_ID_ERROR_INFO:
// 处理错误信息
ProcessErrorInfo(&msg);
break;
default:
// 未知消息ID
break;
}
}
}</code></pre>
</div>
</div>
</div>
</div>
</section>
<!-- 高级应用部分 -->
<section id="advanced" class="mb-12">
<div class="bg-white rounded-xl shadow-card p-6 md:p-8">
<div class="flex items-center mb-6">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-rocket text-primary"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">四、高级应用与优化技巧</h2>
</div>
<!-- 4.1 表达式性能优化 -->
<div id="performance" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">4.1 表达式性能优化</h3>
<p class="text-gray-600 mb-4">在嵌入式系统中,代码效率至关重要。通过优化表达式可以显著提升程序性能,减少资源消耗。</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div class="bg-white rounded-lg border border-gray-200 p-4">
<h5 class="font-medium text-gray-800 mb-2">算术运算优化</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 低效写法
int result = value / 2; // 除法运算较慢
int scaled = value * 10; // 乘法可能不如移位高效
// 优化写法
int result = value >> 1; // 除以2用右移
int scaled = (value << 3) + (value << 1); // 乘以10 = 乘以8 + 乘以2</code></pre>
</div>
<p class="text-gray-600 text-xs">移位运算通常比乘除法更快,尤其在没有硬件乘法器的低端MCU上。</p>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4">
<h5 class="font-medium text-gray-800 mb-2">条件判断优化</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 低效写法
if (mode == 0) {
value = calculate0(param);
} else if (mode == 1) {
value = calculate1(param);
} else if (mode == 2) {
value = calculate2(param);
}
// 优化写法
// 函数指针数组
int (*calculate[])(int) = {
calculate0, calculate1, calculate2
};
value = calculate[mode](param); // 用数组索引替代条件判断</code></pre>
</div>
<p class="text-gray-600 text-xs">使用函数指针数组替代多重条件判断,减少分支跳转,提高缓存利用率。</p>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">位运算优化</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 低效写法
uint8_t flags = 0;
if (error) flags |= 0x01;
if (warning) flags |= 0x02;
if (ready) flags |= 0x04;
if (busy) flags |= 0x08;
// 优化写法
uint8_t flags = (error ? 0x01 : 0) |
(warning ? 0x02 : 0) |
(ready ? 0x04 : 0) |
(busy ? 0x08 : 0);
// 更优写法 - 利用条件表达式的特性
uint8_t flags = (error << 0) | (warning << 1) |
(ready << 2) | (busy << 3);
// 查表法优化范围判断
// 代替 if (x >= 10 && x <= 20) 之类的判断
const uint8_t range_table[32] = {
0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,0,0,0
};
if (range_table[x]) {
// x在10-20范围内
}</code></pre>
</div>
</div>
<div class="bg-secondary p-4 rounded-lg">
<h4 class="font-semibold text-gray-800 mb-2">性能优化最佳实践</h4>
<ul class="space-y-2 text-gray-700">
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>使用 <code class="bg-white px-1 py-0.5 rounded text-xs">const</code> 和 <code class="bg-white px-1 py-0.5 rounded text-xs">volatile</code> 关键字帮助编译器优化</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>避免在循环内部进行复杂计算,将不变的计算移到循环外</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>使用局部变量而非全局变量,提高访问速度和缓存效率</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>对于频繁调用的函数,考虑使用 <code class="bg-white px-1 py-0.5 rounded text-xs">inline</code> 关键字</span>
</li>
<li class="flex items-start">
<i class="fa fa-check-circle text-green-500 mt-1 mr-2"></i>
<span>利用查表法替代复杂计算和多重条件判断</span>
</li>
</ul>
</div>
</div>
<!-- 4.2 安全关键系统中的表达式 -->
<div id="safety" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">4.2 安全关键系统中的表达式</h3>
<p class="text-gray-600 mb-4">在安全关键系统(如汽车、医疗设备)中,表达式的安全性和可靠性至关重要,必须避免未定义行为和潜在错误。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2 flex items-center">
<i class="fa fa-exclamation-triangle text-accent mr-2"></i>
安全关键系统中的禁用表达式
</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 禁用:未定义行为
int i = 5;
int j = i++ + ++i; // 未定义行为,不同编译器结果不同
// 禁用:可能的整数溢出
int32_t a = 2000000000;
int32_t b = 2000000000;
int32_t c = a + b; // 溢出,结果未定义
// 禁用:空指针解引用
int *ptr = NULL;
*ptr = 5; // 空指针解引用,导致硬件错误
// 禁用:除以零
int result = value / 0; // 除以零,导致硬件异常
// 禁用:无边界检查的数组访问
int arr[10];
arr[15] = 0; // 数组越界,覆盖其他内存</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">安全表达式实践</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-2">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 1. 整数运算溢出检查
int32_t safe_add(int32_t a, int32_t b, int32_t *result) {
if(result == NULL) return 0;
// 检查溢出
if((b > 0 && a > INT32_MAX - b) ||
(b < 0 && a < INT32_MIN - b)) {
return 0; // 溢出
}
*result = a + b;
return 1; // 成功
}
// 2. 安全的除法运算
int32_t safe_divide(int32_t numerator, int32_t denominator, int32_t *result) {
if(result == NULL || denominator == 0) return 0;
// 检查溢出(对于有符号整数)
if(numerator == INT32_MIN && denominator == -1) {
return 0; // 溢出
}
*result = numerator / denominator;
return 1; // 成功
}
// 3. 安全的数组访问
uint8_t safe_array_access(uint8_t *array, uint32_t array_size,
uint32_t index, uint8_t *value) {
if(array == NULL || value == NULL) return 0;
// 检查索引是否在有效范围内
if(index >= array_size) return 0;
*value = array[index];
return 1; // 成功
}
// 4. 防重入的单例初始化
#define LOCK() // 实现互斥锁
#define UNLOCK() // 释放互斥锁
static void *singleton_instance = NULL;
static uint8_t initialized = 0;
void *get_singleton(void) {
if(!initialized) {
LOCK(); // 防止多线程/中断重入
if(!initialized) {
// 初始化单例
singleton_instance = malloc(SIZE);
if(singleton_instance != NULL) {
// 初始化操作
initialized = 1;
}
}
UNLOCK();
}
return singleton_instance;
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4">
<h5 class="font-medium text-gray-800 mb-2">安全关键系统编码标准</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<h6 class="font-medium text-gray-700 mb-2 text-sm">MISRA C 关键规则</h6>
<ul class="space-y-1 text-gray-600 text-sm">
<li>• 禁止使用未初始化的变量</li>
<li>• 禁止使用 goto 语句</li>
<li>• 禁止使用动态内存分配(特定情况除外)</li>
<li>• 禁止使用指针运算和指针转换</li>
<li>• 所有循环必须有明确的终止条件</li>
<li>• 函数参数和返回值必须有明确的类型检查</li>
</ul>
</div>
<div>
<h6 class="font-medium text-gray-700 mb-2 text-sm">表达式安全检查清单</h6>
<ul class="space-y-1 text-gray-600 text-sm">
<li>• 所有运算是否有溢出检查?</li>
<li>• 除法和取模运算是否检查除数为零?</li>
<li>• 指针操作是否有非空检查?</li>
<li>• 数组访问是否有边界检查?</li>
<li>• 是否避免了副作用和未定义行为?</li>
<li>• 类型转换是否安全?是否有范围检查?</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 4.3 嵌入式系统特定表达式 -->
<div id="embedded" class="mb-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4">4.3 嵌入式系统特定表达式</h3>
<p class="text-gray-600 mb-4">嵌入式系统有其特殊性,如有限的资源、直接的硬件访问等,需要使用特定的表达式和编程技巧。</p>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">内存映射寄存器访问</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 外设寄存器地址定义
#define PERIPH_BASE ((uint32_t)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
// 寄存器结构体定义
typedef struct {
volatile uint32_t CRL;
volatile uint32_t CRH;
volatile uint32_t IDR;
volatile uint32_t ODR;
volatile uint32_t BSRR;
volatile uint32_t BRR;
volatile uint32_t LCKR;
} GPIO_TypeDef;
// 寄存器指针
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
// 使用示例
void GPIO_Config(void) {
// 使能GPIOA时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 配置PA5为推挽输出
GPIOA->CRL &= ~(GPIO_CRL_MODE5 | GPIO_CRL_CNF5);
GPIOA->CRL |= GPIO_CRL_MODE5_1 | GPIO_CRL_MODE5_0; // 50MHz输出
GPIOA->CRL |= GPIO_CRL_CNF5_0; // 通用推挽输出
}
// 位带操作简化GPIO控制
#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x2000000 + \
((addr & 0x00FFFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
// PA5输出控制
#define PA5_ODR_Addr (GPIOA_BASE + 0x0C)
#define PA5_OUT BIT_ADDR(PA5_ODR_Addr, 5)
// 使用位带操作控制LED
#define LED_ON PA5_OUT = 1
#define LED_OFF PA5_OUT = 0</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4 mb-6">
<h5 class="font-medium text-gray-800 mb-2">中断服务程序优化</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 高效的中断服务程序
volatile uint8_t uart_rx_flag = 0;
volatile uint8_t uart_rx_data;
void USART1_IRQHandler(void) {
// 只处理需要的中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
// 快速读取数据并清除中断标志
uart_rx_data = USART_ReceiveData(USART1);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
// 设置标志位,在主循环中处理
uart_rx_flag = 1;
}
}
// 主循环中处理中断数据
void MainLoop(void) {
while(1) {
// 检查中断标志
if(uart_rx_flag) {
// 清除标志
uart_rx_flag = 0;
// 处理接收到的数据
ProcessUartData(uart_rx_data);
}
// 其他任务...
}
}
// 双缓冲区处理DMA数据
#define BUFFER_SIZE 1024
uint8_t dma_buffer[2][BUFFER_SIZE];
volatile uint8_t active_buffer = 0;
volatile uint8_t buffer_ready[2] = {0, 0};
void DMA1_Channel4_IRQHandler(void) {
// 检查传输完成中断
if(DMA_GetITStatus(DMA1_IT_TC4) != RESET) {
// 清除中断标志
DMA_ClearITPendingBit(DMA1_IT_TC4);
// 标记当前缓冲区为就绪
buffer_ready[active_buffer] = 1;
// 切换到另一个缓冲区
active_buffer ^= 1;
// 重新配置DMA到新缓冲区
DMA_SetCurrDataCounter(DMA1_Channel4, BUFFER_SIZE);
DMA_SetMemoryAddress(DMA1_Channel4, (uint32_t)dma_buffer[active_buffer]);
}
}</code></pre>
</div>
</div>
<div class="bg-white rounded-lg border border-gray-200 p-4">
<h5 class="font-medium text-gray-800 mb-2">低功耗模式控制</h5>
<div class="code-block bg-dark text-white p-3 rounded-md font-mono text-sm mb-3">
<button class="copy-btn bg-gray-700 hover:bg-gray-600 text-white px-2 py-1 rounded text-xs">
<i class="fa fa-copy"></i> 复制
</button>
<pre><code>// 进入低功耗模式
void EnterLowPowerMode(void) {
// 关闭不必要的外设
TIM_Cmd(TIM2, DISABLE);
SPI_Cmd(SPI1, DISABLE);
// 配置唤醒源
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 使能唤醒中断
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 进入停止模式,保留SRAM和寄存器内容
PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
// 从停止模式唤醒后,重新配置系统时钟
RCC_HSEConfig(RCC_HSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
// 重新使能外设
TIM_Cmd(TIM2, ENABLE);
SPI_Cmd(SPI1, ENABLE);
}
// 低功耗定时器配置
void LPTIM_Config(void) {
// 使能LPTIM时钟
RCC->APB1ENR |= RCC_APB1ENR_LPTIM1EN;
// 配置LPTIM时钟源为内部低功耗时钟
LPTIM1->CR = 0;
LPTIM1->CFGR &= ~LPTIM_CFGR_CKSEL;
LPTIM1->CFGR |= LPTIM_CFGR_CKSEL_0; // 内部时钟
// 配置自动重装载值 (1秒)
LPTIM1->ARR = 32767; // 32kHz时钟,约1秒
// 使能中断
LPTIM1->IER |= LPTIM_IER_ARRMIE;
// 使能NVIC中断
NVIC_EnableIRQ(LPTIM1_IRQn);
// 启动计数器
LPTIM1->CR |= LPTIM_CR_CEN;
}
// LPTIM中断服务程序 - 定时唤醒
void LPTIM1_IRQHandler(void) {
if(LPTIM1->ISR & LPTIM_ISR_ARRMCF) {
LPTIM1->ICR |= LPTIM_ICR_ARRMCF; // 清除标志
// 执行定时任务
PeriodicTask();
}
}</code></pre>
</div>
<p class="text-gray-600 text-sm">在电池供电的嵌入式系统中,低功耗模式至关重要。通过精确控制外设和使用低功耗定时器,可以显著延长电池寿命。</p>
</div>
</div>
</div>
</section>
</main>
</div>
<!-- 页脚 -->
<footer class="bg-gray-800 text-white py-8">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<div class="flex items-center">
<i class="fa fa-code text-primary text-2xl mr-2"></i>
<h2 class="text-xl font-bold">C语言表达式全解析</h2>
</div>
<p class="text-gray-400 text-sm mt-2">从基础语法到复杂工程场景的全面指南</p>
</div>
<div class="flex space-x-6">
<a href="#" class="text-gray-400 hover:text-white transition-colors">
<i class="fa fa-github text-xl"></i>
</a>
<a href="#" class="text-gray-400 hover:text-white transition-colors">
<i class="fa fa-twitter text-xl"></i>
</a>
<a href="#" class="text-gray-400 hover:text-white transition-colors">
<i class="fa fa-linkedin text-xl"></i>
</a>
</div>
</div>
<div class="border-t border-gray-700 mt-6 pt-6 text-center text-gray-400 text-sm">
<p>© 2023 C语言表达式解析指南. 保留所有权利.</p>
</div>
</div>
</footer>
<!-- 返回顶部按钮 -->
<button id="back-to-top" class="fixed bottom-6 right-6 bg-primary text-white w-10 h-10 rounded-full flex items-center justify-center shadow-lg opacity-0 transition-opacity duration-300">
<i class="fa fa-arrow-up"></i>
</button>
<script>
// 返回顶部按钮
const backToTopBtn = document.getElementById('back-to-top');
window.addEventListener('scroll', () => {
if (window.pageYOffset > 300) {
backToTopBtn.classList.replace('opacity-0', 'opacity-100');
} else {
backToTopBtn.classList.replace('opacity-100', 'opacity-0');
}
});
backToTopBtn.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
// 滚动时导航栏效果
const header = document.querySelector('header');
let lastScrollTop = 0;
window.addEventListener('scroll', () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop > 100) {
header.classList.add('py-2');
header.classList.remove('py-3');
} else {
header.classList.add('py-3');
header.classList.remove('py-2');
}
lastScrollTop = scrollTop;
});
</script>
</body>
</html>
index.html
style.css
index.js